[REF] sale_purchase: reorganize with hooks
Add a lot of hook to allow a custom module to reuse the standard sale_purchase module. X-original-commit: 89a761bdf84f3a9b06f3504f7ee66540ec0e9f0e Part-of: odoo/odoo#125572
This commit is contained in:
@@ -116,6 +116,9 @@ class SaleOrderLine(models.Model):
|
||||
commitment_date = fields.Datetime.from_string(self.order_id.commitment_date or fields.Datetime.now())
|
||||
return commitment_date - relativedelta(days=int(supplierinfo.delay))
|
||||
|
||||
def _purchase_service_get_company(self):
|
||||
return self.company_id
|
||||
|
||||
def _purchase_service_prepare_order_values(self, supplierinfo):
|
||||
""" Returns the values to create the purchase order from the current SO line.
|
||||
:param supplierinfo: record of product.supplierinfo
|
||||
@@ -128,7 +131,7 @@ class SaleOrderLine(models.Model):
|
||||
return {
|
||||
'partner_id': partner_supplier.id,
|
||||
'partner_ref': partner_supplier.ref,
|
||||
'company_id': self.company_id.id,
|
||||
'company_id': self._purchase_service_get_company().id,
|
||||
'currency_id': partner_supplier.property_purchase_currency_id.id or self.env.company.currency_id.id,
|
||||
'dest_address_id': False, # False since only supported in stock
|
||||
'origin': self.order_id.name,
|
||||
@@ -137,6 +140,37 @@ class SaleOrderLine(models.Model):
|
||||
'fiscal_position_id': fpos.id,
|
||||
}
|
||||
|
||||
def _purchase_service_get_price_unit_and_taxes(self, supplierinfo, purchase_order):
|
||||
supplier_taxes = self.product_id.supplier_taxes_id.filtered(lambda t: t.company_id.id == self.company_id.id)
|
||||
taxes = purchase_order.fiscal_position_id.map_tax(supplier_taxes)
|
||||
if supplierinfo:
|
||||
price_unit = self.env['account.tax'].sudo()._fix_tax_included_price_company(supplierinfo.price, supplier_taxes, taxes, self.company_id)
|
||||
if purchase_order.currency_id and supplierinfo.currency_id != purchase_order.currency_id:
|
||||
price_unit = supplierinfo.currency_id._convert(
|
||||
price_unit,
|
||||
purchase_order.currency_id,
|
||||
purchase_order.company_id,
|
||||
fields.Date.context_today(self)
|
||||
)
|
||||
else:
|
||||
price_unit = 0.0
|
||||
return price_unit, taxes
|
||||
|
||||
def _purchase_service_get_product_name(self, supplierinfo, purchase_order, quantity):
|
||||
product_ctx = {
|
||||
'lang': get_lang(self.env, purchase_order.partner_id.lang).code,
|
||||
'company_id': purchase_order.company_id.id,
|
||||
}
|
||||
if supplierinfo:
|
||||
product_ctx.update({'seller_id': supplierinfo.id})
|
||||
else:
|
||||
product_ctx.update({'partner_id': purchase_order.partner_id.id})
|
||||
product = self.product_id.with_context(**product_ctx)
|
||||
name = product.display_name
|
||||
if product.description_purchase:
|
||||
name += '\n' + product.description_purchase
|
||||
return name
|
||||
|
||||
def _purchase_service_prepare_line_values(self, purchase_order, quantity=False):
|
||||
""" Returns the values to create the purchase order line from the current SO line.
|
||||
:param purchase_order: record of purchase.order
|
||||
@@ -159,28 +193,9 @@ class SaleOrderLine(models.Model):
|
||||
date=purchase_order.date_order and purchase_order.date_order.date(), # and purchase_order.date_order[:10],
|
||||
uom_id=self.product_id.uom_po_id
|
||||
)
|
||||
supplier_taxes = self.product_id.supplier_taxes_id.filtered(lambda t: t.company_id.id == self.company_id.id)
|
||||
taxes = purchase_order.fiscal_position_id.map_tax(supplier_taxes)
|
||||
|
||||
# compute unit price
|
||||
price_unit = 0.0
|
||||
product_ctx = {
|
||||
'lang': get_lang(self.env, purchase_order.partner_id.lang).code,
|
||||
'company_id': purchase_order.company_id,
|
||||
}
|
||||
if supplierinfo:
|
||||
price_unit = self.env['account.tax'].sudo()._fix_tax_included_price_company(
|
||||
supplierinfo.price, supplier_taxes, taxes, self.company_id)
|
||||
if purchase_order.currency_id and supplierinfo.currency_id != purchase_order.currency_id:
|
||||
price_unit = supplierinfo.currency_id._convert(price_unit, purchase_order.currency_id, purchase_order.company_id, fields.Date.context_today(self))
|
||||
product_ctx.update({'seller_id': supplierinfo.id})
|
||||
else:
|
||||
product_ctx.update({'partner_id': purchase_order.partner_id.id})
|
||||
|
||||
product = self.product_id.with_context(**product_ctx)
|
||||
name = product.display_name
|
||||
if product.description_purchase:
|
||||
name += '\n' + product.description_purchase
|
||||
price_unit, taxes = self._purchase_service_get_price_unit_and_taxes(supplierinfo, purchase_order)
|
||||
name = self._purchase_service_get_product_name(supplierinfo, purchase_order, quantity)
|
||||
|
||||
return {
|
||||
'name': name,
|
||||
@@ -188,51 +203,59 @@ class SaleOrderLine(models.Model):
|
||||
'product_id': self.product_id.id,
|
||||
'product_uom': self.product_id.uom_po_id.id,
|
||||
'price_unit': price_unit,
|
||||
'date_planned': fields.Date.from_string(purchase_order.date_order) + relativedelta(days=int(supplierinfo.delay)),
|
||||
'date_planned': purchase_order.date_order + relativedelta(days=int(supplierinfo.delay)),
|
||||
'taxes_id': [(6, 0, taxes.ids)],
|
||||
'order_id': purchase_order.id,
|
||||
'sale_line_id': self.id,
|
||||
}
|
||||
|
||||
def _purchase_service_match_supplier(self, warning=True):
|
||||
# determine vendor of the order (take the first matching company and product)
|
||||
suppliers = self.product_id._select_seller(quantity=self.product_uom_qty, uom_id=self.product_uom)
|
||||
if warning and not suppliers:
|
||||
raise UserError(_("There is no vendor associated to the product %s. Please define a vendor for this product.") % (self.product_id.display_name,))
|
||||
return suppliers[0]
|
||||
|
||||
def _purchase_service_match_purchase_order(self, partner, company=False):
|
||||
return self.env['purchase.order'].search([
|
||||
('partner_id', '=', partner.id),
|
||||
('state', '=', 'draft'),
|
||||
('company_id', '=', (company if company else self.company_id).id),
|
||||
], limit=1)
|
||||
|
||||
def _create_purchase_order(self, supplierinfo):
|
||||
values = self._purchase_service_prepare_order_values(supplierinfo)
|
||||
return self.env['purchase.order'].with_context(mail_create_nosubscribe=True).create(values)
|
||||
|
||||
def _match_or_create_purchase_order(self, supplierinfo):
|
||||
purchase_order = self._purchase_service_match_purchase_order(supplierinfo.partner_id)
|
||||
if not purchase_order:
|
||||
purchase_order = self._create_purchase_order(supplierinfo)
|
||||
return purchase_order
|
||||
|
||||
def _purchase_service_create(self, quantity=False):
|
||||
""" On Sales Order confirmation, some lines (services ones) can create a purchase order line and maybe a purchase order.
|
||||
If a line should create a RFQ, it will check for existing PO. If no one is find, the SO line will create one, then adds
|
||||
a new PO line. The created purchase order line will be linked to the SO line.
|
||||
:param quantity: the quantity to force on the PO line, expressed in SO line UoM
|
||||
"""
|
||||
PurchaseOrder = self.env['purchase.order']
|
||||
supplier_po_map = {}
|
||||
sale_line_purchase_map = {}
|
||||
purchase_lines = self.env['purchase.order.line']
|
||||
for line in self:
|
||||
line = line.with_company(line.company_id)
|
||||
# determine vendor of the order (take the first matching company and product)
|
||||
suppliers = line.product_id._select_seller(quantity=line.product_uom_qty, uom_id=line.product_uom)
|
||||
if not suppliers:
|
||||
raise UserError(_("There is no vendor associated to the product %s. Please define a vendor for this product.") % (line.product_id.display_name,))
|
||||
supplierinfo = suppliers[0]
|
||||
line = line.with_company(line._purchase_service_get_company())
|
||||
supplierinfo = self._purchase_service_match_supplier()
|
||||
partner_supplier = supplierinfo.partner_id
|
||||
|
||||
# determine (or create) PO
|
||||
purchase_order = supplier_po_map.get(partner_supplier.id)
|
||||
if not purchase_order:
|
||||
purchase_order = PurchaseOrder.search([
|
||||
('partner_id', '=', partner_supplier.id),
|
||||
('state', '=', 'draft'),
|
||||
('company_id', '=', line.company_id.id),
|
||||
], limit=1)
|
||||
if not purchase_order:
|
||||
values = line._purchase_service_prepare_order_values(supplierinfo)
|
||||
purchase_order = PurchaseOrder.with_context(mail_create_nosubscribe=True).create(values)
|
||||
else: # update origin of existing PO
|
||||
purchase_order = self._match_or_create_purchase_order(supplierinfo)
|
||||
else: # if not already updated origin in this loop
|
||||
so_name = line.order_id.name
|
||||
origins = []
|
||||
if purchase_order.origin:
|
||||
origins = purchase_order.origin.split(', ') + origins
|
||||
origins = (purchase_order.origin or '').split(', ')
|
||||
if so_name not in origins:
|
||||
origins += [so_name]
|
||||
purchase_order.write({
|
||||
'origin': ', '.join(origins)
|
||||
})
|
||||
purchase_order.write({'origin': ', '.join(origins + [so_name])})
|
||||
supplier_po_map[partner_supplier.id] = purchase_order
|
||||
|
||||
# add a PO line to the PO
|
||||
@@ -244,6 +267,9 @@ class SaleOrderLine(models.Model):
|
||||
sale_line_purchase_map[line] |= purchase_line
|
||||
return sale_line_purchase_map
|
||||
|
||||
|
||||
return purchase_lines
|
||||
|
||||
def _purchase_service_generation(self):
|
||||
""" Create a Purchase for the first time from the sale line. If the SO line already created a PO, it
|
||||
will not create a second one.
|
||||
|
||||
Reference in New Issue
Block a user