diff options
| author | FIN-IT_AndriFP <andrifebriyadiputra@gmail.com> | 2026-02-02 14:55:42 +0700 |
|---|---|---|
| committer | FIN-IT_AndriFP <andrifebriyadiputra@gmail.com> | 2026-02-02 14:55:42 +0700 |
| commit | 52daec6bbde0ff0a239f70069d713ffc9265c2c1 (patch) | |
| tree | bd83bd3805ca664d0f9aaa3cd52c1b32610c445e | |
| parent | 750cdae1141d0039ab2c8d5796c5fb7bb2726bcc (diff) | |
| parent | 50b9bc544cd837772c66ea3314558ef03a09fe21 (diff) | |
Merge branch 'odoo-backup' of https://bitbucket.org/altafixco/indoteknik-addons into odoo-backup
| -rwxr-xr-x | indoteknik_custom/models/purchase_order.py | 13 | ||||
| -rwxr-xr-x | indoteknik_custom/models/purchase_order_line.py | 46 | ||||
| -rw-r--r-- | indoteknik_custom/models/refund_sale_order.py | 55 | ||||
| -rwxr-xr-x | indoteknik_custom/models/sale_order.py | 2 | ||||
| -rw-r--r-- | indoteknik_custom/models/sale_order_line.py | 53 | ||||
| -rw-r--r-- | indoteknik_custom/models/tukar_guling_po.py | 38 | ||||
| -rwxr-xr-x | indoteknik_custom/models/x_manufactures.py | 2 | ||||
| -rwxr-xr-x | indoteknik_custom/views/purchase_order.xml | 1 | ||||
| -rwxr-xr-x | indoteknik_custom/views/sale_order.xml | 1 | ||||
| -rwxr-xr-x | indoteknik_custom/views/x_manufactures.xml | 2 |
10 files changed, 186 insertions, 27 deletions
diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py index e16c8d61..ebe0ae65 100755 --- a/indoteknik_custom/models/purchase_order.py +++ b/indoteknik_custom/models/purchase_order.py @@ -53,6 +53,9 @@ class PurchaseOrder(models.Model): total_so_percent_margin = fields.Float( 'SO Margin%', compute='compute_total_margin', help="Total % Margin in Sales Order Header") + amount_cashback = fields.Float( + 'Cashback', compute='compute_total_margin', + help="Total Cashback brand Altama") amount_total_without_service = fields.Float('AmtTotalWithoutService', compute='compute_amt_total_without_service') summary_qty_po = fields.Float('Total Qty', compute='_compute_summary_qty') summary_qty_receipt = fields.Float('Summary Qty Receipt', compute='_compute_summary_qty') @@ -1407,6 +1410,14 @@ class PurchaseOrder(models.Model): purchase_price += line.delivery_amt_line if line.order_id.delivery_amt > 0: purchase_price += line.order_id.delivery_amt + + cashback_amount = 0.0 + if self.partner_id.id == 5571: + cashback_percent = line.product_id.x_manufacture.cashback_percent or 0.0 + if cashback_percent > 0: + cashback_amount = purchase_price * cashback_percent + purchase_price -= cashback_amount + real_item_margin = sales_price - purchase_price sum_margin += real_item_margin @@ -1415,11 +1426,13 @@ class PurchaseOrder(models.Model): self.total_so_percent_margin = round((sum_so_margin / sum_sales_price), 2) * 100 self.total_margin = sum_margin self.total_percent_margin = round((sum_margin / sum_sales_price), 2) * 100 + self.amount_cashback = cashback_amount else: self.total_margin = 0 self.total_percent_margin = 0 self.total_so_margin = 0 self.total_so_percent_margin = 0 + self.amount_cashback = 0 def compute_total_margin_from_apo(self): sum_so_margin = sum_sales_price = sum_margin = 0 diff --git a/indoteknik_custom/models/purchase_order_line.py b/indoteknik_custom/models/purchase_order_line.py index 8c72887d..76dcc09e 100755 --- a/indoteknik_custom/models/purchase_order_line.py +++ b/indoteknik_custom/models/purchase_order_line.py @@ -23,6 +23,9 @@ class PurchaseOrderLine(models.Model): so_item_percent_margin = fields.Float( 'SO Margin%', compute='compute_item_margin', help="Total % Margin in Sales Order Header") + amount_cashback = fields.Float( + 'SO Margin%', compute='_compute_cashback_brand', + 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') @@ -373,6 +376,9 @@ class PurchaseOrderLine(models.Model): purchase_price = line.price_subtotal if order.delivery_amount > 0: purchase_price += line.delivery_amt_line + + if line.amount_cashback > 0: + purchase_price = purchase_price - line.amount_cashback # Hitung margin dan persentase margin real_item_margin = total_sales_price - purchase_price @@ -384,6 +390,46 @@ class PurchaseOrderLine(models.Model): sum_margin += real_item_margin + def _compute_cashback_brand(self): + start_date = datetime(2026, 2, 1, 0, 0, 0) + + for line in self: + line.amount_cashback = 0.0 + + product = line.product_id + order = line.order_id + + if not product or not order: + continue + + if order.partner_id.id != 5571: + continue + + sales_matches = self.env['purchase.order.sales.match'].search([ + ('purchase_order_id', '=', order.id), + ('product_id', '=', product.id) + ]) + + total_cashback = 0.0 + + for match in sales_matches: + so_line = match.sale_line_id + so_order = so_line.order_id + + if not so_order.date_order or so_order.date_order < start_date: + continue + + cashback_percent = product.x_manufacture.cashback_percent or 0.0 + if cashback_percent <= 0: + continue + sales_price = so_line.price_reduce_taxexcl * match.qty_so + + cashback = sales_price * cashback_percent + total_cashback += cashback + + line.amount_cashback = total_cashback + + def compute_delivery_amt_line(self): for line in self: if line.product_id.type == 'product': diff --git a/indoteknik_custom/models/refund_sale_order.py b/indoteknik_custom/models/refund_sale_order.py index 646376ab..79309694 100644 --- a/indoteknik_custom/models/refund_sale_order.py +++ b/indoteknik_custom/models/refund_sale_order.py @@ -62,7 +62,8 @@ class RefundSaleOrder(models.Model): ('uang', 'Refund Lebih Bayar'), ('retur_half', 'Refund Retur Sebagian'), ('retur', 'Refund Retur Full'), - ('salah_transfer', 'Salah Transfer') + ('salah_transfer', 'Salah Transfer'), + ('berita_acara', 'Kebutuhan Berita Acara') ], string='Refund Type', required=True) tukar_guling_ids = fields.One2many( @@ -242,7 +243,7 @@ class RefundSaleOrder(models.Model): ) invoices = sale_orders.mapped('invoice_ids').filtered( - lambda inv: inv.move_type in ['out_invoice', 'out_refund'] and inv.payment_state == 'paid' + lambda inv: inv.move_type in ['out_invoice', 'out_refund'] and inv.state == 'posted' ) if invoices: vals['invoice_ids'] = [(6, 0, invoices.ids)] @@ -251,7 +252,7 @@ class RefundSaleOrder(models.Model): invoice_ids_data = vals.get('invoice_ids', []) invoice_ids = invoice_ids_data[0][2] if invoice_ids_data and invoice_ids_data[0][0] == 6 else [] invoices = self.env['account.move'].browse(invoice_ids) - if invoice_ids and refund_type and refund_type not in ['uang', 'barang_kosong_sebagian', 'barang_kosong', 'retur_half']: + if invoice_ids and refund_type and refund_type not in ['uang', 'barang_kosong_sebagian', 'barang_kosong', 'retur_half', 'berita_acara']: raise UserError("Refund type Hanya Bisa Lebih Bayar, Barang Kosong Sebagian, atau Retur jika ada invoice") if not invoice_ids and refund_type and refund_type in ['uang', 'barang_kosong_sebagian', 'retur_half']: @@ -434,13 +435,17 @@ class RefundSaleOrder(models.Model): total_invoice = sum(self.env['account.move'].browse(invoice_ids).mapped('amount_total_signed')) if invoice_ids else 0.0 vals['total_invoice'] = total_invoice amount_refund = vals.get('amount_refund', 0.0) - can_refund = sisa_uang_masuk - total_invoice - - if amount_refund > can_refund or can_refund == 0.0: - raise ValidationError( - _("Maksimal refund yang bisa dilakukan adalah sebesar %s. " - "Silakan sesuaikan jumlah refund.") % (can_refund) - ) + can_refund = 0.0 + if refund_type == 'berita_acara': + can_refund = sisa_uang_masuk + else: + can_refund = sisa_uang_masuk - total_invoice + if refund_type != 'berita_acara': + if amount_refund > can_refund or can_refund == 0.0: + raise ValidationError( + _("Maksimal refund yang bisa dilakukan adalah sebesar %s. " + "Silakan sesuaikan jumlah refund.") % (can_refund) + ) if amount_refund <= 0.00: raise ValidationError('Total Refund harus lebih dari 0 jika ingin mengajukan refund') @@ -492,7 +497,7 @@ class RefundSaleOrder(models.Model): valid_invoices = sale_orders.mapped('invoice_ids').filtered( - lambda inv: inv.move_type in ['out_invoice', 'out_refund'] and inv.payment_state == 'paid' + lambda inv: inv.move_type in ['out_invoice', 'out_refund'] and inv.state == 'posted' ) vals['invoice_ids'] = [(6, 0, valid_invoices.ids)] vals['ongkir'] = sum(so.delivery_amt or 0.0 for so in sale_orders) @@ -535,7 +540,7 @@ class RefundSaleOrder(models.Model): else: invoice_ids = rec.invoice_ids.ids - if invoice_ids and vals.get('refund_type', rec.refund_type) not in ['uang', 'barang_kosong_sebagian', 'barang_kosong', 'retur_half', 'retur']: + if invoice_ids and vals.get('refund_type', rec.refund_type) not in ['uang', 'barang_kosong_sebagian', 'barang_kosong', 'retur_half', 'retur', 'berita_acara']: raise UserError("Refund type Hanya Bisa Lebih Bayar, Barang Kosong Sebagian, atau Retur jika ada invoice") if not invoice_ids and vals.get('refund_type', rec.refund_type) in ['uang', 'barang_kosong_sebagian', 'retur_half']: @@ -548,10 +553,28 @@ class RefundSaleOrder(models.Model): if any(field in vals for field in ['uang_masuk', 'invoice_ids', 'ongkir', 'sale_order_ids', 'amount_refund']): total_invoice = sum(self.env['account.move'].browse(invoice_ids).mapped('amount_total_signed')) vals['total_invoice'] = total_invoice - uang_masuk = rec.uang_masuk - can_refund = uang_masuk - total_invoice - + uang_masuk = vals.get('uang_masuk', rec.uang_masuk) amount_refund = vals.get('amount_refund', rec.amount_refund) + can_refund = 0.0 + total_refunded = 0.0 + + if refund_type == 'berita_acara': + can_refund = uang_masuk + remaining = uang_masuk - amount_refund + else: + can_refund = uang_masuk - total_invoice + + existing_refunds = self.search([ + ('sale_order_ids', 'in', so_ids), + ('id', '!=', rec.id) + ]) + total_refunded = sum(existing_refunds.mapped('amount_refund')) + + if existing_refunds: + remaining = uang_masuk - total_refunded + else: + remaining = uang_masuk - amount_refund + if amount_refund > can_refund: raise ValidationError( @@ -708,7 +731,7 @@ class RefundSaleOrder(models.Model): for so in self.sale_order_ids: self.ongkir += so.delivery_amt or 0.0 valid_invoices = so.invoice_ids.filtered( - lambda inv: inv.move_type in ['out_invoice', 'out_refund'] and inv.payment_state == 'paid' + lambda inv: inv.move_type in ['out_invoice', 'out_refund'] and inv.state == 'posted' ) all_invoices |= valid_invoices total_invoice += sum(valid_invoices.mapped('amount_total_signed')) diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 469509d4..a4bc2309 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -3438,7 +3438,7 @@ class SaleOrder(models.Model): def button_refund(self): self.ensure_one() - invoice_ids = self.invoice_ids.filtered(lambda inv: inv.payment_state == 'paid') + invoice_ids = self.invoice_ids.filtered(lambda inv: inv.state == 'posted') moves = self.env['account.move'].search([ ('sale_id', '=', self.id), diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py index 1df1a058..dd44f84a 100644 --- a/indoteknik_custom/models/sale_order_line.py +++ b/indoteknik_custom/models/sale_order_line.py @@ -17,6 +17,7 @@ class SaleOrderLine(models.Model): help="Total % Margin in Sales Order Header") item_percent_margin_before = fields.Float('%Margin Before', compute='_compute_item_percent_margin_before', help="Total % Margin excluding third party in Sales Order Header") + amount_cashback = fields.Float('Cashback Brand', compute='_compute_cashback_brand', help='Cashback from product who has cashback percent in manufacture') initial_discount = fields.Float('Initial Discount') vendor_id = fields.Many2one( 'res.partner', string='Vendor', readonly=True, @@ -164,7 +165,10 @@ class SaleOrderLine(models.Model): purchase_price = line.purchase_price if line.purchase_tax_id.price_include: - purchase_price = line.purchase_price / 1.11 + purchase_price = line.purchase_price / (1 + (line.purchase_tax_id.amount / 100)) + + if line.amount_cashback > 0: + purchase_price = purchase_price - line.amount_cashback purchase_price = purchase_price * line.product_uom_qty margin_per_item = sales_price - purchase_price @@ -186,7 +190,10 @@ class SaleOrderLine(models.Model): purchase_price = line.purchase_price if line.purchase_tax_id and line.purchase_tax_id.price_include: - purchase_price = line.purchase_price / 1.11 + purchase_price = line.purchase_price / (1 + (line.purchase_tax_id.amount / 100)) + + if line.amount_cashback > 0: + purchase_price = purchase_price - line.amount_cashback purchase_price = purchase_price * line.product_uom_qty @@ -215,7 +222,10 @@ class SaleOrderLine(models.Model): purchase_price = line.purchase_price if line.purchase_tax_id.price_include: - purchase_price = line.purchase_price / 1.11 + purchase_price = line.purchase_price / (1 + (line.purchase_tax_id.amount / 100)) + + if line.amount_cashback > 0: + purchase_price = purchase_price - line.amount_cashback purchase_price = purchase_price * line.product_uom_qty margin_per_item = sales_price - purchase_price @@ -241,12 +251,47 @@ class SaleOrderLine(models.Model): purchase_price = line.purchase_price if line.purchase_tax_id.price_include: - purchase_price = line.purchase_price / 1.11 + purchase_price = line.purchase_price / (1 + (line.purchase_tax_id.amount / 100)) + + if line.amount_cashback > 0: + purchase_price = purchase_price - line.amount_cashback purchase_price = purchase_price * line.product_uom_qty margin_per_item = sales_price - purchase_price line.item_before_margin = margin_per_item + def _compute_cashback_brand(self): + start_date = datetime(2026, 2, 1, 0, 0, 0) + for line in self: + line.amount_cashback = 0 + + if not line.product_id: + continue + + if line.order_id.date_order < start_date: + continue + + price, taxes, vendor_id = self._get_purchase_price(line.product_id) + + cashback_percent = line.product_id.x_manufacture.cashback_percent or 0 + if cashback_percent <= 0: + continue + + + if line.vendor_id.id != 5571: + continue + + price_tax_excl = price + + if taxes: + tax = self.env['account.tax'].browse(taxes) + if tax.price_include: + price_tax_excl = price / (1 + (tax.amount / 100)) + else: + price_tax_excl = price + + line.amount_cashback = price_tax_excl * cashback_percent + # @api.onchange('vendor_id') # def onchange_vendor_id(self): # # TODO : need to change this logic @stephan diff --git a/indoteknik_custom/models/tukar_guling_po.py b/indoteknik_custom/models/tukar_guling_po.py index ae58d509..1ee10679 100644 --- a/indoteknik_custom/models/tukar_guling_po.py +++ b/indoteknik_custom/models/tukar_guling_po.py @@ -582,7 +582,23 @@ class TukarGulingPO(models.Model): ('group_id', '=', group.id), ('state', '=', 'done') ]) - bu_inputs = po_pickings.filtered(lambda p: p.picking_type_id.id == 28) + + product_ids = set(record.line_ids.mapped("product_id").ids) + + _logger.info("TG product_ids: %s", product_ids) + + def _get_moves(picking): + return picking.move_ids_without_package if picking.move_ids_without_package else picking.move_lines + + bu_inputs = po_pickings.filtered( + lambda p: p.picking_type_id.id == 28 and any( + m.product_id.id in product_ids + for m in _get_moves(p) + ) + ) + + _logger.info("BU INPUT dengan product sama: %s", bu_inputs.mapped("name")) + bu_puts = po_pickings.filtered(lambda p: p.picking_type_id.id == 75) else: raise UserError("Group ID tidak ditemukan pada BU Operations.") @@ -711,12 +727,26 @@ class TukarGulingPO(models.Model): # Ambil pasangannya di BU INPUT (asumsi urutan sejajar) sorted_bu_puts = sorted(bu_puts, key=lambda p: p.name) + # sorted_bu_inputs = sorted(bu_inputs, key=lambda p: p.name) + + # if bu_put_index >= len(sorted_bu_inputs): + # raise UserError("Tidak ditemukan pasangan BU INPUT untuk BU PUT yang dipilih.") + + # paired = [(sorted_bu_puts[bu_put_index], sorted_bu_inputs[bu_put_index])] sorted_bu_inputs = sorted(bu_inputs, key=lambda p: p.name) - if bu_put_index >= len(sorted_bu_inputs): - raise UserError("Tidak ditemukan pasangan BU INPUT untuk BU PUT yang dipilih.") + if not sorted_bu_inputs: + raise UserError( + "Tidak ditemukan BU INPUT yang memiliki product TG." + ) - paired = [(sorted_bu_puts[bu_put_index], sorted_bu_inputs[bu_put_index])] + paired = [(record.operations, sorted_bu_inputs[0])] + + _logger.info( + "🔗 Pairing BU PUT %s dengan BU INPUT %s", + record.operations.name, + sorted_bu_inputs[0].name + ) for bu_put, bu_input in paired: vrt = _create_return_from_picking(bu_put, bu_put_qty_map) diff --git a/indoteknik_custom/models/x_manufactures.py b/indoteknik_custom/models/x_manufactures.py index 9e214d92..0c3bfa3b 100755 --- a/indoteknik_custom/models/x_manufactures.py +++ b/indoteknik_custom/models/x_manufactures.py @@ -50,7 +50,7 @@ class XManufactures(models.Model): # user_id = fields.Many2one('res.users', string='Responsible', domain="['|'('id', '=', 19), ('id', '=', 6)]", help="Siapa yang bertanggung jawab") user_id = fields.Many2one('res.users', string='Responsible', help="Siapa yang bertanggung jawab") override_vendor_id = fields.Many2one('res.partner', string='Override Vendor') - # cashback_percent = fields.Float(string='Cashback Percent') + cashback_percent = fields.Float(string='Cashback Percent', default=0) def _compute_vendor_ids(self): for manufacture in self: diff --git a/indoteknik_custom/views/purchase_order.xml b/indoteknik_custom/views/purchase_order.xml index 16b8bd44..59e317d2 100755 --- a/indoteknik_custom/views/purchase_order.xml +++ b/indoteknik_custom/views/purchase_order.xml @@ -105,6 +105,7 @@ <field name="amount_total" position="after"> <field name="total_margin"/> <field name="total_so_margin"/> + <field name="amount_cashback"/> <field name="total_percent_margin"/> <field name="total_so_percent_margin"/> </field> diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index 23fbe155..c3df92ec 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -302,6 +302,7 @@ ] } "/> + <field name="amount_cashback"/> <field name="purchase_price_md" optional="hide"/> <field name="purchase_tax_id" attrs="{'readonly': [('parent.approval_status', '!=', False)]}" diff --git a/indoteknik_custom/views/x_manufactures.xml b/indoteknik_custom/views/x_manufactures.xml index d5cec350..b52fe795 100755 --- a/indoteknik_custom/views/x_manufactures.xml +++ b/indoteknik_custom/views/x_manufactures.xml @@ -82,7 +82,7 @@ <field name="x_negara_asal"/> <field name="x_short_desc"/> <field name="x_manufacture_level"/> - <!-- <field name="cashback_percent" widget="percentage"/> --> + <field name="cashback_percent" widget="percentage"/> <field name="x_produk_aksesoris_sparepart"/> <field name="cache_reset_status"/> <field name="parent_id"/> |
