from odoo import fields, models, api, _ from odoo.exceptions import AccessError, UserError, ValidationError from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT import logging from datetime import datetime _logger = logging.getLogger(__name__) class PurchaseOrderLine(models.Model): _inherit = 'purchase.order.line' item_margin = fields.Float( 'Margin', compute='compute_item_margin', help="Total Margin in Sales Order Header") item_percent_margin = fields.Float( 'Margin%', compute='compute_item_margin', help="Total % Margin in Sales Order Header") so_item_margin = fields.Float( 'SO Margin', compute='compute_item_margin', help="Total Margin in Sales Order Header") so_item_percent_margin = fields.Float( 'SO Margin%', compute='compute_item_margin', help="Total % Margin in Sales Order Header") delivery_amt_line = fields.Float('DeliveryAmtLine', compute='compute_delivery_amt_line') line_no = fields.Integer('No', default=0) qty_available = fields.Float('Qty Available', compute='_compute_qty_stock') qty_onhand = fields.Float('Qty On Hand', compute='_compute_qty_stock') qty_incoming = fields.Float('Qty Incoming', compute='_compute_qty_stock') qty_outgoing = fields.Float('Qty Outgoing', compute='_compute_qty_stock') qty_available_store = fields.Float(string='Available') suggest = fields.Char(string='Suggest') price_vendor = fields.Float(string='Price Vendor', compute='compute_price_vendor') so_line_id = fields.Many2one('sale.order.line', string='ID SO Line') indent = fields.Boolean(string='Indent', help='centang ini jika barang indent') is_ltc = fields.Boolean(string='Sudah di LTC', default=False, help='centang ini jika barang sudah di LTC') note = fields.Char(string='Note') sale_automatic_id = fields.Many2one('sale.order', string='SO') qty_reserved = fields.Float(string='Qty Reserved', compute='_compute_qty_reserved') delete_line = fields.Boolean(string='Delete', default=False, help='centang ini jika anda ingin menghapus line ini') is_edit_product_qty = fields.Boolean(string='Is Edit Product Qty', compute='_compute_is_edit_product_qty') @api.constrains('purchase_price') def constrains_purchase_price(self): for line in self: matches_so = self.env['purchase.order.sales.match'].search([ ('purchase_order_id', '=', line.order_id.id), ('product_id', '=', line.product_id.id), ]) line.purchase_price = matches_so.sale_line_id.purchase_price @api.constrains('product_qty') def constrains_product_qty(self): for line in self: qty_po = 0 matches_so = self.env['purchase.order.sales.match'].search([ ('purchase_order_id', '=', line.order_id.id), ('product_id', '=', line.product_id.id), ]) if not matches_so: continue for matches in matches_so: qty_po += matches.qty_po if qty_po == line.product_qty: continue oldest_date_order = min(matches_so.mapped('sale_id.date_order')) oldest_matches = matches_so.filtered(lambda x: x.sale_id.date_order == oldest_date_order) matches_to_remove = matches_so - oldest_matches if matches_to_remove: matches_to_remove.unlink() def unlink(self): for line in self: mathces_so = self.env['purchase.order.sales.match'].search([ ('purchase_order_id', '=', line.order_id.id), ('product_id', '=', line.product_id.id), ]) mathces_so.unlink() return super(PurchaseOrderLine, self).unlink() def _compute_is_edit_product_qty(self): for line in self: if line.order_id.state in ['draft']: is_valid = True else: is_valid = False line.is_edit_product_qty = is_valid # @api.constrains('product_qty') # def change_qty_po_and_qty_demand(self): # for line in self: # if line.order_id.state in ['draft', 'cancel'] and len(line.order_id.picking_ids) == 0: # continue # for stock_picking in line.order_id.picking_ids: # picking = self.env['stock.move'].search([ # ('picking_id.purchase_id', '=', line.order_id.id), # ('product_id', '=', line.product_id.id) # ]) # if picking: # picking.write({ # 'product_uom_qty': line.product_qty # }) def _compute_qty_reserved(self): for line in self: sale_line = self.env['sale.order.line'].search([ ('product_id', '=', line.product_id.id), ('order_id', '=', line.order_id.sale_order_id.id) ]) reserved_qty = sum(line.qty_reserved for line in sale_line) line.qty_reserved = reserved_qty # so_line.qty_reserved (compute) # so_line.qty_reserved = get from picking_ids where type outgoing and prodid = line.prodid # po_line.qty_reserved = cek dulu apakah ada relasi ke sale order. Jika ada maka ambil sesuai yang ada di sale order (so_line.qty_reserved), # jika tidak maka 0 def suggest_purchasing(self): for line in self: if line.product_id.qty_available_bandengan + line.qty_reserved < line.product_qty: line.suggest = 'harus beli' else: line.suggest = 'masih cukup' def compute_price_vendor(self): for line in self: purchase_pricelist = self.env['purchase.pricelist'].search([ ('product_id', '=', line.product_id.id), ('vendor_id', '=', line.order_id.partner_id.id) ], limit=1) if purchase_pricelist: price_vendor = format(purchase_pricelist.product_price, ".2f") price_vendor = float(price_vendor) line.price_vendor = price_vendor else: line.price_vendor = 0 def _compute_qty_stock(self): for line in self: line.qty_available = line.product_id.qty_available_bandengan line.qty_onhand = line.product_id.qty_onhand_bandengan line.qty_incoming = line.product_id.qty_incoming_bandengan line.qty_outgoing = line.product_id.qty_outgoing_bandengan @api.onchange('product_id') def _onchange_product_custom(self): self._compute_qty_stock() @api.onchange('product_id','product_qty', 'product_uom') def _onchange_quantity(self): res = super(PurchaseOrderLine, self)._onchange_quantity() purchase_pricelist = self.env['purchase.pricelist'].search([ ('product_id', '=', self.product_id.id), ('vendor_id', '=', self.partner_id.id), ], limit=1) price_unit = purchase_pricelist.product_price if not price_unit: product_supplierinfo = self.env['product.supplierinfo'].search([ ('product_tmpl_id', '=', self.product_id.product_tmpl_id.id), ('name', '=', self.partner_id.id) ], limit=1) price_unit = product_supplierinfo.price price_unit, taxes = self._get_valid_purchase_price(purchase_pricelist) self.price_unit = price_unit if purchase_pricelist.taxes_product_id or purchase_pricelist.taxes_system_id: self.taxes_id = taxes return res def _get_valid_purchase_price(self, purchase_price): price = 0 taxes = None human_last_update = purchase_price.human_last_update or datetime.min system_last_update = purchase_price.system_last_update or datetime.min if system_last_update > human_last_update: price = purchase_price.system_price taxes = [purchase.taxes_system_id.id for purchase in purchase_price ] else: price = purchase_price.product_price taxes = [purchase.taxes_product_id.id for purchase in purchase_price ] return price, taxes def compute_item_margin(self): sum_so_margin = sum_sales_price = sum_margin = 0 for line in self: if not line.product_id or line.product_id.type == 'service' or not self.order_id.sale_order_id: line.so_item_margin = 0 line.so_item_percent_margin = 0 line.item_margin = 0 line.item_percent_margin = 0 continue sale_order_line = self.env['sale.order.line'].search( [('product_id', '=', line.product_id.id), ('order_id', '=', line.order_id.sale_order_id.id)], limit=1, order='price_reduce_taxexcl') line.so_item_margin = sale_order_line.item_margin line.so_item_percent_margin = sale_order_line.item_percent_margin sum_so_margin += sale_order_line.item_margin sales_price = sale_order_line.price_reduce_taxexcl * sale_order_line.product_uom_qty if sale_order_line.order_id.shipping_cost_covered == 'indoteknik': sales_price -= sale_order_line.delivery_amt_line if sale_order_line.order_id.fee_third_party > 0: sales_price -= sale_order_line.fee_third_party_line sum_sales_price += sales_price purchase_price = line.price_subtotal if line.order_id.delivery_amount > 0: purchase_price += line.delivery_amt_line real_item_margin = sales_price - purchase_price real_item_percent_margin = round((real_item_margin/sales_price), 2) * 100 line.item_margin = real_item_margin line.item_percent_margin = real_item_percent_margin sum_margin += real_item_margin def compute_delivery_amt_line(self): for line in self: if line.product_id.type == 'product': contribution = round((line.price_total / line.order_id.amount_total_without_service), 2) delivery_amt = line.order_id.delivery_amount line.delivery_amt_line = delivery_amt * contribution else: line.delivery_amt_line = 0