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.

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