diff options
| -rw-r--r-- | indoteknik_custom/models/commision.py | 16 | ||||
| -rwxr-xr-x | indoteknik_custom/models/sale_order.py | 93 | ||||
| -rw-r--r-- | indoteknik_custom/models/sale_order_line.py | 19 | ||||
| -rw-r--r-- | indoteknik_custom/models/solr/product_template.py | 2 | ||||
| -rw-r--r-- | indoteknik_custom/models/stock_move.py | 1 | ||||
| -rw-r--r-- | indoteknik_custom/models/stock_picking.py | 6 | ||||
| -rwxr-xr-x | indoteknik_custom/views/sale_order.xml | 19 |
7 files changed, 130 insertions, 26 deletions
diff --git a/indoteknik_custom/models/commision.py b/indoteknik_custom/models/commision.py index 32e81b9a..bd4c06a4 100644 --- a/indoteknik_custom/models/commision.py +++ b/indoteknik_custom/models/commision.py @@ -1,8 +1,10 @@ from odoo import models, api, fields, _ from odoo.exceptions import UserError from datetime import datetime +# import datetime import logging from terbilang import Terbilang +import pytz _logger = logging.getLogger(__name__) @@ -301,30 +303,34 @@ class CustomerCommision(models.Model): return result def action_confirm_customer_commision(self): - now = datetime.utcnow() + jakarta_tz = pytz.timezone('Asia/Jakarta') + now = datetime.now(jakarta_tz) + + now_naive = now.replace(tzinfo=None) + if not self.status or self.status == 'draft': self.status = 'pengajuan1' elif self.status == 'pengajuan1' and self.env.user.is_sales_manager: self.status = 'pengajuan2' self.approved_by = (self.approved_by + ', ' if self.approved_by else '') + self.env.user.name - self.date_approved_sales = now + self.date_approved_sales = now_naive self.position_sales = 'Sales Manager' elif self.status == 'pengajuan2' and self.env.user.id == 19: self.status = 'pengajuan3' self.approved_by = (self.approved_by + ', ' if self.approved_by else '') + self.env.user.name - self.date_approved_marketing = now + self.date_approved_marketing = now_naive self.position_marketing = 'Marketing Manager' elif self.status == 'pengajuan3' and self.env.user.is_leader: self.status = 'pengajuan4' self.approved_by = (self.approved_by + ', ' if self.approved_by else '') + self.env.user.name - self.date_approved_pimpinan = now + self.date_approved_pimpinan = now_naive self.position_pimpinan = 'Pimpinan' elif self.status == 'pengajuan4' and self.env.user.id == 1272: for line in self.commision_lines: line.invoice_id.is_customer_commision = True self.status = 'approved' self.approved_by = (self.approved_by + ', ' if self.approved_by else '') + self.env.user.name - self.date_approved_accounting = now + self.date_approved_accounting = now_naive self.position_accounting = 'Accounting' else: raise UserError('Harus di approved oleh yang bersangkutan') diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 4c48684d..f99058ea 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -133,8 +133,9 @@ class SaleOrder(models.Model): reject_line = fields.One2many('sales.order.reject', 'sale_order_id', string='Reject Lines') order_sales_match_line = fields.One2many('sales.order.purchase.match', 'sales_order_id', string='Purchase Match Lines', states={'cancel': [('readonly', True)], 'done': [('readonly', True)]}, copy=True) total_margin = fields.Float('Total Margin', compute='_compute_total_margin', help="Total Margin in Sales Order Header") + total_before_margin = fields.Float('Total Before Margin', compute='_compute_total_before_margin', help="Total Margin in Sales Order Header") total_percent_margin = fields.Float('Total Percent Margin', compute='_compute_total_percent_margin', help="Total % Margin in Sales Order Header") - total_margin_excl_third_party = fields.Float('Before Margin', help="Before Margin in Sales Order Header") + total_margin_excl_third_party = fields.Float('Before Margin', help="Before Margin in Sales Order Header", compute='_compute_total_margin_excl_third_party') approval_status = fields.Selection([ ('pengajuan1', 'Approval Manager'), ('pengajuan2', 'Approval Pimpinan'), @@ -202,9 +203,9 @@ class SaleOrder(models.Model): customer_type = fields.Selection([ ('pkp', 'PKP'), ('nonpkp', 'Non PKP') - ], required=True) - sppkp = fields.Char(string="SPPKP", required=True, tracking=True) - npwp = fields.Char(string="NPWP", required=True, tracking=True) + ], required=True, compute='_compute_partner_field') + sppkp = fields.Char(string="SPPKP", required=True, tracking=True, compute='_compute_partner_field') + npwp = fields.Char(string="NPWP", required=True, tracking=True, compute='_compute_partner_field') purchase_total = fields.Monetary(string='Purchase Total', compute='_compute_purchase_total') voucher_id = fields.Many2one(comodel_name='voucher', string='Voucher', copy=False) applied_voucher_id = fields.Many2one(comodel_name='voucher', string='Applied Voucher', copy=False) @@ -296,6 +297,54 @@ class SaleOrder(models.Model): ) nomor_so_pengganti = fields.Char(string='Nomor SO Pengganti', copy=False, tracking=3) shipping_option_id = fields.Many2one("shipping.option", string="Selected Shipping Option", domain="['|', ('sale_order_id', '=', False), ('sale_order_id', '=', id)]") + hold_outgoing = fields.Boolean('Hold Outgoing SO') + state_ask_cancel = fields.Selection([ + ('hold', 'Hold'), + ('approve', 'Approve') + ], tracking=True, string='State Cancel', copy=False) + + def _compute_total_margin_excl_third_party(self): + for order in self: + if order.amount_untaxed == 0: + order.total_margin_excl_third_party = 0 + continue + + # order.total_percent_margin = round((order.total_margin / (order.amount_untaxed-delivery_amt-order.fee_third_party)) * 100, 2) + order.total_margin_excl_third_party = round((order.total_before_margin / (order.amount_untaxed)) * 100, 2) + # order.total_percent_margin = round((order.total_margin / (order.amount_untaxed)) * 100, 2) + + def ask_retur_cancel_purchasing(self): + for rec in self: + if self.env.user.has_group('indoteknik_custom.group_role_purchasing'): + rec.state_ask_cancel = 'approve' + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'title': 'Persetujuan Diberikan', + 'message': 'Proses cancel sudah disetujui', + 'type': 'success', + 'sticky': True + } + } + else: + rec.state_ask_cancel = 'hold' + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'title': 'Menunggu Persetujuan', + 'message': 'Tim Purchasing akan memproses permintaan Anda', + 'type': 'warning', + 'sticky': False + } + } + + def hold_unhold_qty_outgoing_so(self): + if self.hold_outgoing == True: + self.hold_outgoing = False + else: + self.hold_outgoing = True def _validate_uniform_taxes(self): for order in self: @@ -307,17 +356,17 @@ class SaleOrder(models.Model): if len(tax_sets) > 1: raise ValidationError("Semua produk dalam Sales Order harus memiliki kombinasi pajak yang sama.") - @api.constrains('fee_third_party', 'delivery_amt', 'biaya_lain_lain') - def _check_total_margin_excl_third_party(self): - for rec in self: - if rec.fee_third_party == 0 and rec.total_margin_excl_third_party != rec.total_percent_margin: - # Gunakan direct SQL atau flag context untuk menghindari rekursi - self.env.cr.execute(""" - UPDATE sale_order - SET total_margin_excl_third_party = %s - WHERE id = %s - """, (rec.total_percent_margin, rec.id)) - self.invalidate_cache() + # @api.constrains('fee_third_party', 'delivery_amt', 'biaya_lain_lain') + # def _check_total_margin_excl_third_party(self): + # for rec in self: + # if rec.fee_third_party == 0 and rec.total_margin_excl_third_party != rec.total_percent_margin: + # # Gunakan direct SQL atau flag context untuk menghindari rekursi + # self.env.cr.execute(""" + # UPDATE sale_order + # SET total_margin_excl_third_party = %s + # WHERE id = %s + # """, (rec.total_percent_margin, rec.id)) + # self.invalidate_cache() @api.constrains('shipping_option_id') def _check_shipping_option(self): @@ -994,6 +1043,13 @@ class SaleOrder(models.Model): # return [('id', 'not in', order_ids)] # return ['&', ('order_line.invoice_lines.move_id.move_type', 'in', ('out_invoice', 'out_refund')), ('order_line.invoice_lines.move_id', operator, value)] + @api.depends('partner_id') + def _compute_partner_field(self): + for order in self: + partner = order.partner_id.parent_id or order.partner_id + order.npwp = partner.npwp + order.sppkp = partner.sppkp + order.customer_type = partner.customer_type @api.onchange('partner_id') def onchange_partner_contact(self): @@ -1441,6 +1497,8 @@ class SaleOrder(models.Model): def action_cancel(self): # TODO stephan prevent cancel if have invoice, do, and po + if self.state_ask_cancel != 'approve' and self.state not in ['draft', 'sent']: + raise UserError("Anda harus approval purchasing terlebih dahulu") main_parent = self.partner_id.get_main_parent() if self._name != 'sale.order': return super(SaleOrder, self).action_cancel() @@ -1560,6 +1618,11 @@ class SaleOrder(models.Model): order.total_margin = total_margin + def _compute_total_before_margin(self): + for order in self: + total_before_margin = sum(line.item_before_margin for line in order.order_line if line.product_id) + order.total_before_margin = total_before_margin + def _compute_total_percent_margin(self): for order in self: if order.amount_untaxed == 0: diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py index aed95aab..2450abd4 100644 --- a/indoteknik_custom/models/sale_order_line.py +++ b/indoteknik_custom/models/sale_order_line.py @@ -6,6 +6,7 @@ from datetime import datetime, timedelta class SaleOrderLine(models.Model): _inherit = 'sale.order.line' item_margin = fields.Float('Margin', compute='compute_item_margin', help="Total Margin in Sales Order Header") + item_before_margin = fields.Float('Before Margin', compute='compute_item_before_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") initial_discount = fields.Float('Initial Discount') vendor_id = fields.Many2one( @@ -146,6 +147,24 @@ class SaleOrderLine(models.Model): if not line.margin_md: line.margin_md = line.item_percent_margin + def compute_item_before_margin(self): + for line in self: + if not line.product_id or line.product_id.type == 'service' \ + or line.price_unit <= 0 or line.product_uom_qty <= 0 \ + or not line.vendor_id: + line.item_before_margin = 0 + continue + # calculate margin without tax + sales_price = line.price_reduce_taxexcl * line.product_uom_qty + + purchase_price = line.purchase_price + if line.purchase_tax_id.price_include: + purchase_price = line.purchase_price / 1.11 + + purchase_price = purchase_price * line.product_uom_qty + margin_per_item = sales_price - purchase_price + line.item_before_margin = margin_per_item + @api.onchange('vendor_id') def onchange_vendor_id(self): # TODO : need to change this logic @stephan diff --git a/indoteknik_custom/models/solr/product_template.py b/indoteknik_custom/models/solr/product_template.py index 20402c84..c4aefe19 100644 --- a/indoteknik_custom/models/solr/product_template.py +++ b/indoteknik_custom/models/solr/product_template.py @@ -100,7 +100,7 @@ class ProductTemplate(models.Model): "product_rating_f": template.virtual_rating, "product_id_i": template.id, "image_s": self.env['ir.attachment'].api_image('product.template', 'image_512', template.id), - "image_carousel_ss": carousel_images, + "image_carousel_ss": carousel_images if carousel_images else [], 'image_mobile_s': self.env['ir.attachment'].api_image('product.template', 'image_256', template.id), "variant_total_i": template.product_variant_count, "stock_total_f": template.qty_stock_vendor, diff --git a/indoteknik_custom/models/stock_move.py b/indoteknik_custom/models/stock_move.py index 3c765244..90ab30a4 100644 --- a/indoteknik_custom/models/stock_move.py +++ b/indoteknik_custom/models/stock_move.py @@ -14,6 +14,7 @@ class StockMove(models.Model): qr_code_variant = fields.Binary("QR Code Variant", compute='_compute_qr_code_variant') barcode = fields.Char(string='Barcode', related='product_id.barcode') vendor_id = fields.Many2one('res.partner' ,string='Vendor') + hold_outgoingg = fields.Boolean('Hold Outgoing', default=False) # @api.model_create_multi # def create(self, vals_list): diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index ce1399fe..f431d817 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -973,6 +973,8 @@ class StockPicking(models.Model): if self.env.user.is_accounting: pick.approval_return_status = 'approved' continue + else: + pick.approval_return_status = 'pengajuan1' action = self.env['ir.actions.act_window']._for_xml_id('indoteknik_custom.action_stock_return_note_wizard') @@ -1241,8 +1243,8 @@ class StockPicking(models.Model): if not invoice: continue - - if not picking.so_lama and (not picking.date_doc_kirim or not invoice.invoice_date): + + if not picking.so_lama and invoice and (not picking.date_doc_kirim or not invoice.invoice_date): raise UserError("Tanggal Kirim atau Tanggal Invoice belum diisi!") picking_date = fields.Date.to_date(picking.date_doc_kirim) diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index 10c60e24..ed389b4c 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -16,6 +16,16 @@ type="object" attrs="{'invisible': [('approval_status', '=', ['approved'])]}" /> + <button name="hold_unhold_qty_outgoing_so" + string="Hold/Unhold Outgoing" + type="object" + attrs="{'invisible': [('state', 'in', ['cancel'])]}" + /> + <button name="ask_retur_cancel_purchasing" + string="Ask Cancel Purchasing" + type="object" + attrs="{'invisible': [('state', 'in', ['cancel'])]}" + /> <button name="action_web_approve" string="Web Approve" type="object" @@ -83,6 +93,7 @@ <attribute name="invisible">1</attribute> </field> <field name="user_id" position="after"> + <field name="hold_outgoing" readonly="1" /> <field name="helper_by_id" readonly="1" /> <field name="compute_fullfillment" invisible="1" /> </field> @@ -98,9 +109,9 @@ <field name="pareto_status" /> </field> <field name="analytic_account_id" position="after"> - <field name="customer_type" required="1" /> - <field name="npwp" placeholder='99.999.999.9-999.999' required="1" /> - <field name="sppkp" attrs="{'required': [('customer_type', '=', 'pkp')]}" /> + <field name="customer_type" readonly="1" /> + <field name="npwp" placeholder='99.999.999.9-999.999' readonly="1" /> + <field name="sppkp" attrs="{'required': [('customer_type', '=', 'pkp')]}" readonly="1" /> <field name="email" required="1" /> <field name="unreserve_id" /> <field name="due_id" readonly="1" /> @@ -271,6 +282,7 @@ </div> <field name="total_margin" /> <field name="total_percent_margin" /> + <field name="total_before_margin" /> </field> <field name="effective_date" position="after"> <field name="carrier_id" /> @@ -383,6 +395,7 @@ <field name="payment_status" optional="hide" /> <field name="pareto_status" optional="hide" /> <field name="shipping_method_picking" optional="hide" /> + <field name="hold_outgoing" optional="hide" /> </field> </field> </record> |
