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.

337 lines
11 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. # Copyright 2020 Coop IT Easy SCRL fs
  2. # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
  3. import logging
  4. import uuid
  5. from datetime import date
  6. from odoo import api, fields, models
  7. from odoo.exceptions import UserError, ValidationError
  8. from odoo.tools.translate import _
  9. _logger = logging.getLogger(__name__)
  10. class BeesdooProduct(models.Model):
  11. _inherit = "product.template"
  12. eco_label = fields.Many2one(
  13. "beesdoo.product.label", domain=[("type", "=", "eco")]
  14. )
  15. local_label = fields.Many2one(
  16. "beesdoo.product.label", domain=[("type", "=", "local")]
  17. )
  18. fair_label = fields.Many2one(
  19. "beesdoo.product.label", domain=[("type", "=", "fair")]
  20. )
  21. origin_label = fields.Many2one(
  22. "beesdoo.product.label", domain=[("type", "=", "delivery")]
  23. )
  24. main_seller_id = fields.Many2one(
  25. "res.partner",
  26. string="Main Seller",
  27. compute="_compute_main_seller_id",
  28. store=True,
  29. )
  30. display_unit = fields.Many2one("uom.uom")
  31. default_reference_unit = fields.Many2one("uom.uom")
  32. display_weight = fields.Float(
  33. compute="_compute_display_weight", store=True
  34. )
  35. total_with_vat = fields.Float(
  36. compute="_compute_total",
  37. store=True,
  38. string="Total Sales Price with VAT",
  39. )
  40. total_with_vat_by_unit = fields.Float(
  41. compute="_compute_total",
  42. store=True,
  43. string="Total Sales Price with VAT by Reference Unit",
  44. )
  45. total_deposit = fields.Float(
  46. compute="_compute_total", store=True, string="Deposit Price"
  47. )
  48. label_to_be_printed = fields.Boolean("Print label?")
  49. label_last_printed = fields.Datetime("Label last printed on")
  50. note = fields.Text("Comments")
  51. # S0023 : List_price = Price HTVA, so add a suggested price
  52. list_price = fields.Float(string="exVAT Price")
  53. suggested_price = fields.Float(
  54. string="Suggested exVAT Price", compute="_compute_cost", readOnly=True
  55. )
  56. deadline_for_sale = fields.Integer(string="Deadline for sale(days)")
  57. deadline_for_consumption = fields.Integer(
  58. string="Deadline for consumption(days)"
  59. )
  60. ingredients = fields.Char(string="Ingredient")
  61. scale_label_info_1 = fields.Char(string="Scale lable info 1")
  62. scale_label_info_2 = fields.Char(string="Scale lable info 2")
  63. scale_sale_unit = fields.Char(
  64. compute="_compute_scale_sale_uom", string="Scale sale unit", store=True
  65. )
  66. scale_category = fields.Many2one(
  67. "beesdoo.scale.category", string="Scale Category"
  68. )
  69. scale_category_code = fields.Integer(
  70. related="scale_category.code",
  71. string="Scale category code",
  72. readonly=True,
  73. store=True,
  74. )
  75. @api.depends("uom_id", "uom_id.category_id", "uom_id.category_id.type")
  76. @api.multi
  77. def _compute_scale_sale_uom(self):
  78. for product in self:
  79. if product.uom_id.category_id.type == "unit":
  80. product.scale_sale_unit = "F"
  81. elif product.uom_id.category_id.type == "weight":
  82. product.scale_sale_unit = "P"
  83. def _get_main_supplier_info(self):
  84. far_future = date(3000, 1, 1)
  85. def sort_date_first(seller):
  86. if seller.date_start:
  87. return seller.date_start
  88. else:
  89. return far_future
  90. suppliers = self.seller_ids.sorted(key=sort_date_first, reverse=True)
  91. if suppliers:
  92. return suppliers[0]
  93. else:
  94. return suppliers
  95. @api.multi
  96. def generate_barcode(self):
  97. self.ensure_one()
  98. if self.to_weight:
  99. seq_internal_code = self.env.ref(
  100. "beesdoo_product.seq_ean_product_internal_ref"
  101. )
  102. bc = ""
  103. if not self.default_code:
  104. rule = self.env["barcode.rule"].search(
  105. [
  106. (
  107. "name",
  108. "=",
  109. "Price Barcodes (Computed Weight) 2 Decimals",
  110. )
  111. ]
  112. )[0]
  113. default_code = seq_internal_code.next_by_id()
  114. while (
  115. self.search_count([("default_code", "=", default_code)])
  116. > 1
  117. ):
  118. default_code = seq_internal_code.next_by_id()
  119. self.default_code = default_code
  120. ean = "02" + self.default_code[0:5] + "000000"
  121. bc = ean[0:12] + str(
  122. self.env["barcode.nomenclature"].ean_checksum(ean)
  123. )
  124. else:
  125. rule = self.env["barcode.rule"].search(
  126. [("name", "=", "Beescoop Product Barcodes")]
  127. )[0]
  128. size = 13 - len(rule.pattern)
  129. ean = rule.pattern + str(uuid.uuid4().fields[-1])[:size]
  130. bc = ean[0:12] + str(
  131. self.env["barcode.nomenclature"].ean_checksum(ean)
  132. )
  133. # Make sure there is no other active member with the same barcode
  134. while self.search_count([("barcode", "=", bc)]) > 1:
  135. ean = rule.pattern + str(uuid.uuid4().fields[-1])[:size]
  136. bc = ean[0:12] + str(
  137. self.env["barcode.nomenclature"].ean_checksum(ean)
  138. )
  139. _logger.info("barcode :", bc)
  140. self.barcode = bc
  141. @api.multi
  142. @api.depends("seller_ids", "seller_ids.date_start")
  143. def _compute_main_seller_id(self):
  144. for product in self:
  145. # Calcule le vendeur associé qui a la date de début la plus récente
  146. # et plus petite qu’aujourd’hui
  147. sellers_ids = product._get_main_supplier_info()
  148. product.main_seller_id = (
  149. sellers_ids and sellers_ids[0].name or False
  150. )
  151. @api.multi
  152. @api.depends(
  153. "taxes_id",
  154. "list_price",
  155. "taxes_id.amount",
  156. "taxes_id.tax_group_id",
  157. "display_weight",
  158. "weight",
  159. )
  160. def _compute_total(self):
  161. for product in self:
  162. consignes_group = self.env.ref(
  163. "beesdoo_product.consignes_group_tax", raise_if_not_found=False
  164. )
  165. taxes_included = set(product.taxes_id.mapped("price_include"))
  166. if len(taxes_included) == 0:
  167. product.total_with_vat = product.list_price
  168. return True
  169. elif len(taxes_included) > 1:
  170. raise ValidationError(
  171. _("Several tax strategies (price_include) defined for %s")
  172. % product.name
  173. )
  174. elif taxes_included.pop():
  175. product.total_with_vat = product.list_price
  176. product.total_deposit = sum(
  177. [
  178. tax._compute_amount(
  179. product.list_price, product.list_price
  180. )
  181. for tax in product.taxes_id
  182. if tax.tax_group_id == consignes_group
  183. ]
  184. )
  185. else:
  186. tax_amount_sum = sum(
  187. [
  188. tax._compute_amount(
  189. product.list_price, product.list_price
  190. )
  191. for tax in product.taxes_id
  192. if tax.tax_group_id != consignes_group
  193. ]
  194. )
  195. product.total_with_vat = product.list_price + tax_amount_sum
  196. product.total_deposit = sum(
  197. [
  198. tax._compute_amount(product.list_price, product.list_price)
  199. for tax in product.taxes_id
  200. if tax.tax_group_id == consignes_group
  201. ]
  202. )
  203. if product.display_weight > 0:
  204. product.total_with_vat_by_unit = (
  205. product.total_with_vat / product.weight
  206. )
  207. @api.multi
  208. @api.depends("weight", "display_unit")
  209. def _compute_display_weight(self):
  210. for product in self:
  211. product.display_weight = (
  212. product.weight * product.display_unit.factor
  213. )
  214. @api.multi
  215. @api.constrains("display_unit", "default_reference_unit")
  216. def _unit_same_category(self):
  217. for product in self:
  218. if (
  219. product.display_unit.category_id
  220. != product.default_reference_unit.category_id
  221. ):
  222. raise UserError(
  223. _(
  224. "Reference Unit and Display Unit should belong to the "
  225. "same category "
  226. )
  227. )
  228. @api.multi
  229. @api.depends("seller_ids")
  230. def _compute_cost(self):
  231. for product in self:
  232. suppliers = product._get_main_supplier_info()
  233. if len(suppliers) > 0:
  234. product.suggested_price = (
  235. suppliers[0].price * product.uom_po_id.factor
  236. ) * (
  237. 1
  238. + suppliers[0].product_tmpl_id.categ_id.profit_margin / 100
  239. )
  240. class BeesdooScaleCategory(models.Model):
  241. _name = "beesdoo.scale.category"
  242. _description = "beesdoo.scale.category"
  243. name = fields.Char(string="Scale name category")
  244. code = fields.Integer(string="Category code")
  245. _sql_constraints = [
  246. (
  247. "code_scale_categ_uniq",
  248. "unique (code)",
  249. "The code of the scale category must be unique !",
  250. )
  251. ]
  252. class BeesdooProductLabel(models.Model):
  253. _name = "beesdoo.product.label"
  254. _description = "beesdoo.product.label"
  255. name = fields.Char()
  256. type = fields.Selection(
  257. [
  258. ("eco", "Écologique"),
  259. ("local", "Local"),
  260. ("fair", "Équitable"),
  261. ("delivery", "Distribution"),
  262. ]
  263. )
  264. color_code = fields.Char()
  265. active = fields.Boolean(default=True)
  266. class BeesdooProductCategory(models.Model):
  267. _inherit = "product.category"
  268. profit_margin = fields.Float(default="10.0", string="Product Margin [%]")
  269. @api.multi
  270. @api.constrains("profit_margin")
  271. def _check_margin(self):
  272. for product in self:
  273. if product.profit_margin < 0.0:
  274. raise UserError(_("Percentages for Profit Margin must > 0."))
  275. class BeesdooProductSupplierInfo(models.Model):
  276. _inherit = "product.supplierinfo"
  277. price = fields.Float("exVAT Price")
  278. class BeesdooUOMCateg(models.Model):
  279. _inherit = "uom.category"
  280. type = fields.Selection(
  281. [
  282. ("unit", "Unit"),
  283. ("weight", "Weight"),
  284. ("time", "Time"),
  285. ("distance", "Distance"),
  286. ("surface", "Surface"),
  287. ("volume", "Volume"),
  288. ("other", "Other"),
  289. ],
  290. string="Category type",
  291. default="unit",
  292. )