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.

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