from odoo import models, fields, api, tools, _ from datetime import datetime, timedelta import math import logging from odoo.exceptions import AccessError, UserError, ValidationError class MrpProduction(models.Model): _inherit = 'mrp.production' desc = fields.Text(string='Description') sale_order = fields.Many2one('sale.order', string='Sale Order', required=True, copy=False) production_purchase_match = fields.One2many('production.purchase.match', 'production_id', string='Purchase Matches', auto_join=True) is_po = fields.Boolean(string='Is PO') def action_confirm(self): """Override action_confirm untuk mengirim pesan ke Sale Order jika state berubah menjadi 'confirmed'.""" if self._name != 'mrp.production': return super(MrpProduction, self).action_confirm() result = super(MrpProduction, self).action_confirm() for record in self: if record.sale_order and record.state == 'confirmed': message = _("Manufacturing order telah dibuat dengan nomor %s") % (record.name) record.sale_order.message_post(body=message) return result def create_po_from_manufacturing(self): if not self.state == 'confirmed': raise UserError('Harus Di Approve oleh Merchandiser') if self.is_po == True: raise UserError('Sudah pernah di buat PO') if not self.move_raw_ids: raise UserError('Tidak ada Lines, belum bisa create PO') # if self.is_po: # raise UserError('Sudah pernah di create PO') vendor_ids = self.env['stock.move'].read_group([ ('raw_material_production_id', '=', self.id), ('vendor_id', '!=', False) ], fields=['vendor_id'], groupby=['vendor_id']) po_ids = [] for vendor in vendor_ids: result_po = self.create_po_by_vendor(vendor['vendor_id'][0]) po_ids += result_po return { 'name': _('Purchase Order'), 'view_mode': 'tree,form', 'res_model': 'purchase.order', 'target': 'current', 'type': 'ir.actions.act_window', 'domain': [('id', 'in', po_ids)], } def create_po_by_vendor(self, vendor_id): current_time = datetime.now() PRODUCT_PER_PO = 20 stock_move = self.env['stock.move'] param_header = { 'partner_id': vendor_id, # 'partner_ref': self.sale_order_id.name, 'currency_id': 12, 'user_id': self.env.user.id, 'company_id': 1, # indoteknik dotcom gemilang 'picking_type_id': 28, # indoteknik bandengan receipts 'date_order': current_time, 'product_bom_id': self.product_id.id, # 'sale_order_id': self.sale_order_id.id, 'note_description': 'from Manufacturing Order' } domain = [ ('raw_material_production_id', '=', self.id), ('vendor_id', '=', vendor_id), ('state', 'in', ['waiting','confirmed','partially_available']) ] products_len = stock_move.search_count(domain) page = math.ceil(products_len / PRODUCT_PER_PO) po_ids = [] # i start from zero (0) for i in range(page): new_po = self.env['purchase.order'].create([param_header]) new_po.name = new_po.name + "/MO/" + str(i + 1) po_ids.append(new_po.id) lines = stock_move.search( domain, offset=i * PRODUCT_PER_PO, limit=PRODUCT_PER_PO ) tax = [22] for line in lines: product = line.product_id price, taxes, vendor = self._get_purchase_price(product) param_line = { 'order_id' : new_po.id, 'product_id': product.id, 'product_qty': line.product_uom_qty if line.state in ['confirmed', 'waiting'] else line.product_uom_qty - line.forecast_availability, 'product_uom_qty': line.product_uom_qty if line.state in ['confirmed', 'waiting'] else line.product_uom_qty - line.forecast_availability, 'name': product.display_name, 'price_unit': price if price else 0.0, 'taxes_id': [taxes] if taxes else [], } new_po_line = self.env['purchase.order.line'].create([param_line]) self.env['production.purchase.match'].create([{ 'production_id': self.id, 'order_id': new_po.id }]) self.is_po = True return po_ids def _get_purchase_price(self, product_id): override_vendor = product_id.x_manufacture.override_vendor_id query = [('product_id', '=', product_id.id), ('vendor_id', '=', override_vendor.id)] purchase_price = self.env['purchase.pricelist'].search(query, limit=1) if purchase_price: return self._get_valid_purchase_price(purchase_price) else: purchase_price = self.env['purchase.pricelist'].search( [('product_id', '=', product_id.id), ('is_winner', '=', True)], limit=1) return self._get_valid_purchase_price(purchase_price) def _get_valid_purchase_price(self, purchase_price): current_time = datetime.now() delta_time = current_time - timedelta(days=365) # delta_time = delta_time.strftime('%Y-%m-%d %H:%M:%S') price = 0 taxes = '' vendor_id = '' human_last_update = purchase_price.human_last_update or datetime.min system_last_update = purchase_price.system_last_update or datetime.min if purchase_price.taxes_product_id.type_tax_use == 'purchase': price = purchase_price.product_price taxes = purchase_price.taxes_product_id.id vendor_id = purchase_price.vendor_id.id if delta_time > human_last_update: price = 0 taxes = '' vendor_id = '' if system_last_update > human_last_update: if purchase_price.taxes_system_id.type_tax_use == 'purchase': price = purchase_price.system_price taxes = purchase_price.taxes_system_id.id vendor_id = purchase_price.vendor_id.id if delta_time > system_last_update: price = 0 taxes = '' vendor_id = '' return price, taxes, vendor_id class ProductionPurchaseMatch(models.Model): _name = 'production.purchase.match' _order = 'production_id, id' production_id = fields.Many2one('mrp.production', string='Ref', required=True, ondelete='cascade', index=True, copy=False) order_id = fields.Many2one('purchase.order', string='Purchase Order') vendor = fields.Char(string='Vendor', compute='_compute_info_po') total = fields.Float(string='Total', compute='_compute_info_po') def _compute_info_po(self): for match in self: match.vendor = match.order_id.partner_id.name match.total = match.order_id.amount_total