diff options
| -rwxr-xr-x | indoteknik_custom/models/purchase_order.py | 146 | ||||
| -rwxr-xr-x | indoteknik_custom/models/sale_order.py | 7 | ||||
| -rw-r--r-- | indoteknik_custom/models/stock_picking.py | 4 | ||||
| -rwxr-xr-x | indoteknik_custom/security/ir.model.access.csv | 1 | ||||
| -rwxr-xr-x | indoteknik_custom/views/purchase_order.xml | 43 | ||||
| -rwxr-xr-x | indoteknik_custom/views/sale_order.xml | 1 | ||||
| -rw-r--r-- | indoteknik_custom/views/stock_picking.xml | 4 |
7 files changed, 180 insertions, 26 deletions
diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py index 45134939..27aca0d1 100755 --- a/indoteknik_custom/models/purchase_order.py +++ b/indoteknik_custom/models/purchase_order.py @@ -92,6 +92,11 @@ class PurchaseOrder(models.Model): is_cab_visible = fields.Boolean(string='Tampilkan Tombol CAB', compute='_compute_is_cab_visible') + reason_change_date_planned = fields.Selection([ + ('delay', 'Delay By Vendor'), + ('urgent', 'Urgent Delivery'), + ], string='Reason Change Date Planned', tracking=True) + # picking_ids = fields.One2many('stock.picking', 'purchase_id', string='Pickings') bu_related_count = fields.Integer( @@ -100,9 +105,68 @@ class PurchaseOrder(models.Model): ) manufacturing_id = fields.Many2one('mrp.production', string='Manufacturing Orders') + complete_bu_in_count = fields.Integer( + string="Complete BU In Count", + compute='_compute_complete_bu_in_count' + ) + + def _compute_complete_bu_in_count(self): + for order in self: + if order.state not in ['done', 'cancel']: + order.complete_bu_in_count = 1 + else: + relevant_pickings = order.picking_ids.filtered( + lambda p: p.state != 'done' + and p.state != 'cancel' + and p.picking_type_code == 'incoming' + and p.origin == order.name + and p.name.startswith('BU/IN') + ) + order.complete_bu_in_count = len(relevant_pickings) + def _has_vcm(self): if self.id: self.vcm_id = self.env['tukar.guling.po'].search([('origin', '=', self.name)], limit=1) + + @api.depends('order_line.date_planned') + def _compute_date_planned(self): + """ date_planned = the earliest date_planned across all order lines. """ + for order in self: + order.date_planned = False + + @api.constrains('date_planned') + def constrains_date_planned(self): + for rec in self: + if not self.env.user.has_group('indoteknik_custom.group_role_purchasing'): + raise ValidationError("Hanya dapat diisi oleh Purchasing") + + base_bu = self.env['stock.picking'].search([ + ('name', 'ilike', 'BU/'), + ('origin', 'ilike', rec.name), + ('group_id', '=', rec.group_id.id), + ('state', 'not in', ['cancel','done']) + ]) + + for bu in base_bu: + bu.write({ + 'scheduled_date': rec.date_planned, + 'reason_change_date_planned': rec.reason_change_date_planned + }) + + rec.sync_date_planned_to_so() + + def sync_date_planned_to_so(self): + for line in self.order_sales_match_line: + other_sales_match = self.env['purchase.order.sales.match'].search([ + # ('product_id', '=', line.product_id.id), + ('sale_id', '=', line.sale_id.id), + # ('sale_line_id', '=', line.sale_line_id.id) + ]) + + dates = [d for d in other_sales_match.mapped('purchase_order_id.date_planned') if d] + if dates: + date_planned = max(dates) + line.sale_id.write({'et_products': date_planned, 'reason_change_date_planned': line.purchase_order_id.reason_change_date_planned}) @api.depends('name') def _compute_bu_related_count(self): @@ -677,13 +741,6 @@ class PurchaseOrder(models.Model): for order in self: order.has_active_invoice = any(invoice.state != 'cancel' for invoice in order.invoice_ids) - # def _compute_has_active_invoice(self): - # for order in self: - # related_invoices = order.invoice_ids.filtered( - # lambda inv: inv.purchase_order_id.id == order.id and inv.move_type == 'in_invoice' and inv.state != 'cancel' - # ) - # order.has_active_invoice = bool(related_invoices) - def add_product_to_pricelist(self): i = 0 for line in self.order_line: @@ -766,16 +823,16 @@ class PurchaseOrder(models.Model): """ purchase_pricelist.message_post(body=message, subtype_id=self.env.ref("mail.mt_note").id) - def _compute_date_planned(self): - for order in self: - if order.date_approve: - leadtime = order.partner_id.leadtime - current_time = order.date_approve - delta_time = current_time + timedelta(days=leadtime) - delta_time = delta_time.strftime('%Y-%m-%d %H:%M:%S') - order.date_planned = delta_time - else: - order.date_planned = False + # def _compute_date_planned(self): + # for order in self: + # if order.date_approve: + # leadtime = order.partner_id.leadtime + # current_time = order.date_approve + # delta_time = current_time + timedelta(days=leadtime) + # delta_time = delta_time.strftime('%Y-%m-%d %H:%M:%S') + # order.date_planned = delta_time + # else: + # order.date_planned = False def action_create_invoice(self): res = super(PurchaseOrder, self).action_create_invoice() @@ -959,6 +1016,9 @@ class PurchaseOrder(models.Model): if self.amount_untaxed >= 50000000 and not self.env.user.id == 21: raise UserError("Hanya Rafly Hanggara yang bisa approve") + + if not self.date_planned: + raise UserError("Receipt Date harus diisi") if self.total_percent_margin < self.total_so_percent_margin: self.env.user.notify_danger( @@ -975,7 +1035,7 @@ class PurchaseOrder(models.Model): # ) if not self.from_apo: - if (not self.matches_so or not self.sale_order_id) and not self.env.user.is_purchasing_manager and not self.env.user.is_leader and not self.manufacturing_id: + if not self.matches_so and not self.env.user.is_purchasing_manager and not self.env.user.is_leader: raise UserError("Tidak ada link dengan SO, harus di confirm oleh Purchasing Manager") send_email = False @@ -1010,10 +1070,10 @@ class PurchaseOrder(models.Model): self.approve_by = self.env.user.id # override date planned added with two days - leadtime = self.partner_id.leadtime - delta_time = current_time + timedelta(days=leadtime) - delta_time = delta_time.strftime('%Y-%m-%d %H:%M:%S') - self.date_planned = delta_time + # leadtime = self.partner_id.leadtime + # delta_time = current_time + timedelta(days=leadtime) + # delta_time = delta_time.strftime('%Y-%m-%d %H:%M:%S') + # self.date_planned = delta_time self.date_deadline_ref_date_planned() self.unlink_purchasing_job_state() @@ -1391,6 +1451,20 @@ class PurchaseOrder(models.Model): # Tambahkan pemanggilan method untuk handle pricelist system update self._handle_pricelist_system_update(vals) return res + + def action_open_change_date_wizard(self): + self.ensure_one() + return { + 'type': 'ir.actions.act_window', + 'res_model': 'change.date.planned.wizard', + 'view_mode': 'form', + 'target': 'new', + 'context': { + 'default_purchase_id': self.id, + 'default_new_date_planned': self.date_planned, + } + } + def _handle_pricelist_system_update(self, vals): if 'order_line' in vals or any(key in vals for key in ['state', 'approval_status']): @@ -1479,4 +1553,32 @@ class PurchaseOrderUnlockWizard(models.TransientModel): order.approval_status_unlock = 'pengajuanFinance' return {'type': 'ir.actions.act_window_close'} +class ChangeDatePlannedWizard(models.TransientModel): + _name = 'change.date.planned.wizard' + _description = 'Change Date Planned Wizard' + + purchase_id = fields.Many2one('purchase.order', string="Purchase Order", required=True) + new_date_planned = fields.Datetime(string="New Date Planned") # <- harus DTTM biar match + old_date_planned = fields.Datetime(string="Current Planned Date", related='purchase_id.date_planned', readonly=True) + reason = fields.Selection([ + ('delay', 'Delay By Vendor'), + ('urgent', 'Urgent Delivery'), + ], string='Reason') + date_changed = fields.Boolean(string="Date Changed", compute="_compute_date_changed") + + @api.depends('old_date_planned', 'new_date_planned') + def _compute_date_changed(self): + for rec in self: + rec.date_changed = ( + rec.old_date_planned and rec.new_date_planned and + rec.old_date_planned != rec.new_date_planned + ) + + def confirm_change(self): + self.purchase_id.write({ + 'date_planned': self.new_date_planned, + 'reason_change_date_planned': self.reason, + }) + + diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 7be0e8ff..4e36a9fb 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -350,7 +350,7 @@ class SaleOrder(models.Model): date_unhold = fields.Datetime(string='Date Unhold', tracking=True, readonly=True, help='Waktu ketika SO di Unhold' ) - et_products = fields.Datetime(string='ET Products', compute='_compute_et_products', help="Leadtime produk berdasarkan SLA vendor, tanpa logistik.") + et_products = fields.Datetime(string='ET Products', help="Leadtime produk berdasarkan SLA vendor, tanpa logistik.", tracking=True) eta_date_reserved = fields.Datetime( string="Date Reserved", @@ -381,6 +381,11 @@ class SaleOrder(models.Model): if self.id: self.ccm_id = self.env['tukar.guling'].search([('origin', 'ilike', self.name)], limit=1) + reason_change_date_planned = fields.Selection([ + ('delay', 'Delay By Vendor'), + ('urgent', 'Urgent Delivery'), + ], string='Reason Change Date Planned', tracking=True) + @api.depends('order_line.product_id', 'date_order') def _compute_et_products(self): jakarta = pytz.timezone("Asia/Jakarta") diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 3e152f10..5dd5844d 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -303,6 +303,10 @@ class StockPicking(models.Model): approval_invoice_date_id = fields.Many2one('approval.invoice.date', string='Approval Invoice Date') last_update_date_doc_kirim = fields.Datetime(string='Last Update Tanggal Kirim', copy=False) update_date_doc_kirim_add = fields.Boolean(string='Update Tanggal Kirim Lewat ADD') + reason_change_date_planned = fields.Selection([ + ('delay', 'Delay By Vendor'), + ('urgent', 'Urgent Delivery'), + ], string='Reason Change Date Planned', tracking=True) def _get_kgx_awb_number(self): """Menggabungkan name dan origin untuk membuat AWB Number""" diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index 015b257c..9b43bf2a 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -161,6 +161,7 @@ access_konfirm_koli,access.konfirm.koli,model_konfirm_koli,,1,1,1,1 access_stock_immediate_transfer,access.stock.immediate.transfer,model_stock_immediate_transfer,,1,1,1,1 access_coretax_faktur,access.coretax.faktur,model_coretax_faktur,,1,1,1,1 access_purchase_order_unlock_wizard,access.purchase.order.unlock.wizard,model_purchase_order_unlock_wizard,,1,1,1,1 +access_change_date_planned_wizard,access.change.date.planned.wizard,model_change_date_planned_wizard,,1,1,1,1 access_sales_order_koli,access.sales.order.koli,model_sales_order_koli,,1,1,1,1 access_stock_backorder_confirmation,access.stock.backorder.confirmation,model_stock_backorder_confirmation,,1,1,1,1 access_warning_modal_wizard,access.warning.modal.wizard,model_warning_modal_wizard,,1,1,1,1 diff --git a/indoteknik_custom/views/purchase_order.xml b/indoteknik_custom/views/purchase_order.xml index ff223125..fedcb4f9 100755 --- a/indoteknik_custom/views/purchase_order.xml +++ b/indoteknik_custom/views/purchase_order.xml @@ -75,11 +75,13 @@ </field> <field name="partner_id" position="after"> <field name="purchase_order_count"/> + <field name="complete_bu_in_count" invisible="1"/> </field> <field name="incoterm_id" position="after"> <field name="amount_total_without_service"/> <field name="delivery_amt"/> <field name="approve_by"/> + <field name="reason_change_date_planned"/> </field> <field name="currency_id" position="after"> <field name="summary_qty_po"/> @@ -106,9 +108,16 @@ <field name="product_id" position="attributes"> <attribute name="options">{'no_create': True}</attribute> </field> - <field name="date_planned" position="attributes"> - <attribute name="invisible">1</attribute> - </field> + <xpath expr="//field[@name='date_planned']" position="replace"> + <field name="date_planned" readonly="1"/> + </xpath> + <xpath expr="//field[@name='date_planned']" position="after"> + <button name="action_open_change_date_wizard" + type="object" + string="Change Receipt Date" + class="btn-primary" + attrs="{'invisible': ['|', ('state', '=', 'cancel'), ('complete_bu_in_count', '=', 0)]}"/> + </xpath> <field name="product_qty" position="before"> <field name="is_edit_product_qty" readonly="1" optional="hide"/> <field name="qty_onhand" readonly="1" optional="hide"/> @@ -225,6 +234,34 @@ </data> <data> + <record id="view_change_date_planned_wizard_form" model="ir.ui.view"> + <field name="name">change.date.planned.wizard.form</field> + <field name="model">change.date.planned.wizard</field> + <field name="arch" type="xml"> + <form string="Change Date Planned"> + <group> + <field name="purchase_id" readonly="1"/> + <field name="old_date_planned" readonly="1"/> + <field name="date_changed" invisible="1"/> + <field name="new_date_planned"/> + <field name="reason" + attrs="{ + 'invisible': ['|', ('old_date_planned', '=', False), ('date_changed', '=', False)], + 'required': [('date_changed', '=', True)] + }"/> + </group> + + <footer> + <button name="confirm_change" type="object" string="Confirm" class="btn-primary"/> + <button string="Cancel" class="btn-secondary" special="cancel"/> + </footer> + </form> + </field> + </record> + </data> + + + <data> <record id="rfq_order_tree_view_inherit" model="ir.ui.view"> <field name="name">Purchase</field> <field name="model">purchase.order</field> diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index c1f1fe61..d8017734 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -172,6 +172,7 @@ <xpath expr="//page[@name='other_information']/group/group[@name='sale_reporting']" position="after"> <group string="ETA"> <field name="et_products"/> + <field name="reason_change_date_planned" readonly="1"/> <field name="eta_date_reserved"/> <field name="expected_ready_to_ship"/> <field name="eta_date_start"/> diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml index f9200dfa..b3f0ce9f 100644 --- a/indoteknik_custom/views/stock_picking.xml +++ b/indoteknik_custom/views/stock_picking.xml @@ -129,6 +129,9 @@ <field name="date_done" position="after"> <field name="arrival_time"/> </field> + <field name="scheduled_date" position="attributes"> + <attribute name="readonly">1</attribute> + </field> <field name="origin" position="after"> <!-- <field name="show_state_approve_md" invisible="1" optional="hide"/>--> <field name="state_approve_md" widget="badge"/> @@ -165,6 +168,7 @@ <field name="approval_receipt_status"/> <field name="approval_return_status"/> <field name="so_lama"/> + <field name="reason_change_date_planned" readonly="1"/> </field> <field name="product_id" position="before"> <field name="line_no" attrs="{'readonly': 1}" optional="hide"/> |
