You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
5.7 KiB

  1. # Copyright 2016 Nicolas Bessi, Camptocamp SA
  2. # Copyright 2018 Tecnativa - Pedro M. Baeza
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  4. from lxml import etree
  5. from odoo import _, api, fields, models
  6. from odoo.exceptions import ValidationError
  7. class ResPartner(models.Model):
  8. _inherit = "res.partner"
  9. zip_id = fields.Many2one(
  10. comodel_name="res.city.zip",
  11. string="ZIP Location",
  12. index=True,
  13. compute="_compute_zip_id",
  14. readonly=False,
  15. store=True,
  16. )
  17. city_id = fields.Many2one(
  18. index=True, # add index for performance
  19. compute="_compute_city_id",
  20. readonly=False,
  21. store=True,
  22. )
  23. city = fields.Char(compute="_compute_city", readonly=False, store=True)
  24. zip = fields.Char(compute="_compute_zip", readonly=False, store=True)
  25. country_id = fields.Many2one(
  26. compute="_compute_country_id", readonly=False, store=True
  27. )
  28. state_id = fields.Many2one(compute="_compute_state_id", readonly=False, store=True)
  29. @api.depends("state_id", "country_id", "city_id", "zip")
  30. def _compute_zip_id(self):
  31. """Empty the zip auto-completion field if data mismatch when on UI."""
  32. for record in self.filtered("zip_id"):
  33. fields_map = {
  34. "zip": "name",
  35. "city_id": "city_id",
  36. "state_id": "state_id",
  37. "country_id": "country_id",
  38. }
  39. for rec_field, zip_field in fields_map.items():
  40. if (
  41. record[rec_field]
  42. and record[rec_field] != record._origin[rec_field]
  43. and record[rec_field] != record.zip_id[zip_field]
  44. ):
  45. record.zip_id = False
  46. break
  47. @api.depends("zip_id")
  48. def _compute_city_id(self):
  49. if hasattr(super(), "_compute_city_id"):
  50. super()._compute_city_id() # pragma: no cover
  51. for record in self:
  52. if record.zip_id:
  53. record.city_id = record.zip_id.city_id
  54. elif not record.country_enforce_cities:
  55. record.city_id = False
  56. @api.depends("zip_id")
  57. def _compute_city(self):
  58. if hasattr(super(), "_compute_city"):
  59. super()._compute_city() # pragma: no cover
  60. for record in self:
  61. if record.zip_id:
  62. record.city = record.zip_id.city_id.name
  63. @api.depends("zip_id")
  64. def _compute_zip(self):
  65. if hasattr(super(), "_compute_zip"):
  66. super()._compute_zip() # pragma: no cover
  67. for record in self:
  68. if record.zip_id:
  69. record.zip = record.zip_id.name
  70. @api.depends("zip_id", "state_id")
  71. def _compute_country_id(self):
  72. if hasattr(super(), "_compute_country_id"):
  73. super()._compute_country_id() # pragma: no cover
  74. for record in self:
  75. if record.zip_id.city_id.country_id:
  76. record.country_id = record.zip_id.city_id.country_id
  77. elif record.state_id:
  78. record.country_id = record.state_id.country_id
  79. @api.depends("zip_id")
  80. def _compute_state_id(self):
  81. if hasattr(super(), "_compute_state_id"):
  82. super()._compute_state_id() # pragma: no cover
  83. for record in self:
  84. state = record.zip_id.city_id.state_id
  85. if state and record.state_id != state:
  86. record.state_id = record.zip_id.city_id.state_id
  87. @api.constrains("zip_id", "country_id", "city_id", "state_id", "zip")
  88. def _check_zip(self):
  89. if self.env.context.get("skip_check_zip"):
  90. return
  91. for rec in self:
  92. if not rec.zip_id:
  93. continue
  94. if rec.zip_id.city_id.country_id != rec.country_id:
  95. raise ValidationError(
  96. _("The country of the partner %s differs from that in location %s")
  97. % (rec.name, rec.zip_id.name)
  98. )
  99. if rec.zip_id.city_id.state_id != rec.state_id:
  100. raise ValidationError(
  101. _("The state of the partner %s differs from that in location %s")
  102. % (rec.name, rec.zip_id.name)
  103. )
  104. if rec.zip_id.city_id != rec.city_id:
  105. raise ValidationError(
  106. _("The city of partner %s differs from that in location %s")
  107. % (rec.name, rec.zip_id.name)
  108. )
  109. if rec.zip_id.name != rec.zip:
  110. raise ValidationError(
  111. _("The zip of the partner %s differs from that in location %s")
  112. % (rec.name, rec.zip_id.name)
  113. )
  114. def _zip_id_domain(self):
  115. return """
  116. [
  117. ("city_id", "=?", city_id),
  118. ("city_id.country_id", "=?", country_id),
  119. ("city_id.state_id", "=?", state_id),
  120. ]
  121. """
  122. @api.model
  123. def _fields_view_get_address(self, arch):
  124. # We want to use a domain that requires city_id to be on the view
  125. # but we can't add it directly there, otherwise _fields_view_get_address
  126. # in base_address_city won't do its magic, as it immediately returns
  127. # if city_id is already in there. On the other hand, if city_id is not in the
  128. # views, odoo won't let us use it in zip_id's domain.
  129. # For this reason we need to set the domain here.
  130. arch = super()._fields_view_get_address(arch)
  131. doc = etree.fromstring(arch)
  132. for node in doc.xpath("//field[@name='zip_id']"):
  133. node.attrib["domain"] = self._zip_id_domain()
  134. return etree.tostring(doc, encoding="unicode")
  135. @api.model
  136. def _address_fields(self):
  137. return super()._address_fields() + ["zip_id", "city_id"]