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.

351 lines
11 KiB

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