diff options
| author | Miqdad <ahmadmiqdad27@gmail.com> | 2025-09-15 13:40:46 +0700 |
|---|---|---|
| committer | Miqdad <ahmadmiqdad27@gmail.com> | 2025-09-15 13:40:46 +0700 |
| commit | 2f835b71aaad9d2d6fef1fafcb600bf50b034f2b (patch) | |
| tree | 1e4463e3b4fd8f86231625253152bc2a8d7ea215 /indoteknik_custom/models/sale_order.py | |
| parent | a47bdc61945b8ab153d80590f06975210f8d2a80 (diff) | |
| parent | cf64a8c5913308c3121a55b1b4cd1acf17c86d73 (diff) | |
Merge branch 'odoo-backup' of https://bitbucket.org/altafixco/indoteknik-addons into cbd-apt
merge
Diffstat (limited to 'indoteknik_custom/models/sale_order.py')
| -rwxr-xr-x | indoteknik_custom/models/sale_order.py | 242 |
1 files changed, 151 insertions, 91 deletions
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 77fee068..e7dd582d 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -234,9 +234,9 @@ class SaleOrder(models.Model): customer_type = fields.Selection([ ('pkp', 'PKP'), ('nonpkp', 'Non PKP') - ], 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') + ], related="partner_id.customer_type", string="Customer Type", readonly=True) + sppkp = fields.Char(string="SPPKP", related="partner_id.sppkp") + npwp = fields.Char(string="NPWP", related="partner_id.npwp") 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) @@ -358,7 +358,6 @@ class SaleOrder(models.Model): help="Tanggal pertama kali barang berhasil di-reservasi pada DO (BU/PICK/) yang berstatus Siap Dikirim." ) refund_ids = fields.Many2many('refund.sale.order', compute='_compute_refund_ids', string='Refunds') - has_refund = fields.Boolean(string='Has Refund', compute='_compute_has_refund') refund_count = fields.Integer(string='Refund Count', compute='_compute_refund_count') advance_payment_move_id = fields.Many2one( 'account.move', @@ -394,6 +393,26 @@ class SaleOrder(models.Model): ('paid', 'Full Paid'), ('no_invoice', 'No Invoice'), ], string="Payment Status Invoice", compute="_compute_payment_state_custom", store=False) + partner_is_cbd_locked = fields.Boolean( + string="Partner Locked CBD", + compute="_compute_partner_is_cbd_locked" + ) + + @api.depends('partner_id.is_cbd_locked') + def _compute_partner_is_cbd_locked(self): + for order in self: + order.partner_is_cbd_locked = order.partner_id.is_cbd_locked + + + @api.constrains('payment_term_id', 'partner_id', 'state') + def _check_cbd_lock_sale_order(self): + # cbd_term = self.env['account.payment.term'].browse(26) + for rec in self: + if rec.state == 'draft' and rec.partner_id.is_cbd_locked: + # if rec.payment_term_id and rec.payment_term_id != cbd_term: + raise ValidationError( + "Customer ini terkunci ke CBD, hanya boleh pakai Payment Term CBD." + ) @api.depends('invoice_ids.payment_state', 'invoice_ids.amount_total', 'invoice_ids.amount_residual') def _compute_payment_state_custom(self): @@ -2030,22 +2049,22 @@ 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.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): parent_id = self.partner_id.parent_id parent_id = parent_id if parent_id else self.partner_id - self.npwp = parent_id.npwp - self.sppkp = parent_id.sppkp - self.customer_type = parent_id.customer_type + # self.npwp = parent_id.npwp + # self.sppkp = parent_id.sppkp + # self.customer_type = parent_id.customer_type self.email = parent_id.email self.pareto_status = parent_id.pareto_status self.user_id = parent_id.user_id @@ -2116,15 +2135,21 @@ class SaleOrder(models.Model): if self.payment_term_id.id == 31 and self.total_percent_margin < 25: raise UserError("Jika ingin menggunakan Tempo 90 Hari maka margin harus di atas 25%") - if self.warehouse_id.id != 8 and self.warehouse_id.id != 10: # GD Bandengan - raise UserError('Gudang harus Bandengan') + if self.warehouse_id.id != 8 and self.warehouse_id.id != 10 and self.warehouse_id.id != 12: # GD Bandengan / Pameran + raise UserError('Gudang harus Bandengan atau Pameran') if self.state not in ['draft', 'sent']: raise UserError("Status harus draft atau sent") - self._validate_npwp() - def _validate_npwp(self): + if not self.npwp: + raise UserError("NPWP partner kosong, silahkan isi terlebih dahulu npwp nya di contact partner") + + if not self.customer_type: + raise UserError("Customer Type partner kosong, silahkan isi terlebih dahulu Customer Type nya di contact partner") + + if not self.sppkp: + raise UserError("SPPKP partner kosong, silahkan isi terlebih dahulu SPPKP nya di contact partner") num_digits = sum(c.isdigit() for c in self.npwp) if num_digits < 10: @@ -2138,6 +2163,7 @@ class SaleOrder(models.Model): self._validate_order() for order in self: + order._validate_npwp() order._validate_uniform_taxes() order.order_line.validate_line() @@ -2192,9 +2218,8 @@ class SaleOrder(models.Model): if self.validate_different_vendor() and not self.vendor_approval: return self._create_notification_action('Notification', 'Terdapat Vendor yang berbeda dengan MD Vendor') self.check_due() - - self._validate_order() for order in self: + order._validate_npwp() order._validate_delivery_amt() order._validate_uniform_taxes() order.order_line.validate_line() @@ -2467,6 +2492,7 @@ class SaleOrder(models.Model): order.check_data_real_delivery_address() order.sale_order_check_approve() order._validate_order() + order._validate_npwp() order.order_line.validate_line() main_parent = order.partner_id.get_main_parent() @@ -2652,23 +2678,17 @@ class SaleOrder(models.Model): def _set_sppkp_npwp_contact(self): partner = self.partner_id.parent_id or self.partner_id - if not partner.sppkp: - partner.sppkp = self.sppkp - if not partner.npwp: - partner.npwp = self.npwp + # if not partner.sppkp: + # partner.sppkp = self.sppkp + # if not partner.npwp: + # partner.npwp = self.npwp if not partner.email: partner.email = self.email - if not partner.customer_type: - partner.customer_type = self.customer_type + # if not partner.customer_type: + # partner.customer_type = self.customer_type if not partner.user_id: partner.user_id = self.user_id.id - # if not partner.sppkp or not partner.npwp or not partner.email or partner.customer_type: - # partner.customer_type = self.customer_type - # partner.npwp = self.npwp - # partner.sppkp = self.sppkp - # partner.email = self.email - def _compute_total_margin(self): for order in self: total_margin = sum(line.item_margin for line in order.order_line if line.product_id) @@ -3110,52 +3130,6 @@ class SaleOrder(models.Model): # order._update_partner_details() return order - # def write(self, vals): - # Call the super method to handle the write operation - # res = super(SaleOrder, self).write(vals) - # self._compute_etrts_date() - # Check if the update is coming from a save operation - # if any(field in vals for field in ['sppkp', 'npwp', 'email', 'customer_type']): - # self._update_partner_details() - - # return res - - def _update_partner_details(self): - for order in self: - partner = order.partner_id.parent_id or order.partner_id - if partner: - # Update partner details - partner.sppkp = order.sppkp - partner.npwp = order.npwp - partner.email = order.email - partner.customer_type = order.customer_type - - # Save changes to the partner record - partner.write({ - 'sppkp': partner.sppkp, - 'npwp': partner.npwp, - 'email': partner.email, - 'customer_type': partner.customer_type, - }) - - # def write(self, vals): - # for order in self: - # if order.state in ['sale', 'cancel']: - # if 'order_line' in vals: - # new_lines = vals.get('order_line', []) - # for command in new_lines: - # if command[0] == 0: # A new line is being added - # raise UserError( - # "SO tidak dapat ditambahkan produk baru karena SO sudah menjadi sale order.") - # - # res = super(SaleOrder, self).write(vals) - # # self._check_total_margin_excl_third_party() - # if any(fields in vals for fields in ['delivery_amt', 'carrier_id', 'shipping_cost_covered']): - # self._validate_delivery_amt() - # if any(field in vals for field in ["order_line", "client_order_ref"]): - # self._calculate_etrts_date() - # return res - # @api.depends('commitment_date') def _compute_ready_to_ship_status_detail(self): def is_empty(val): @@ -3284,20 +3258,58 @@ class SaleOrder(models.Model): def button_refund(self): self.ensure_one() + if self.state not in ['cancel', 'sale']: + raise UserError(f"❌ SO {self.name} tidak bisa direfund. Status harus Cancel atau Sale.") + if self.state == 'sale': + not_done_pickings = self.picking_ids.filtered(lambda p: p.state not in ['done', 'cancel']) + if not_done_pickings: + raise UserError( + f"❌ SO {self.name} Belum melakukan kirim barang " + f"({', '.join(not_done_pickings.mapped('name'))}). Selesaikan Pengiriman untuk melakukan refund." + ) + moves = self.env['account.move'].search([ + ('sale_id', '=', self.id), + ('journal_id', '=', 11), + ('state', '=', 'posted'), + ]) + + # Default 0 + total_uang_muka = 0.0 + + has_moves = bool(moves) + has_settlement = self.payment_status == 'settlement' + + if has_moves and has_settlement: + total_uang_muka = sum(moves.mapped('amount_total_signed')) + self.gross_amount + elif has_moves: + total_uang_muka = sum(moves.mapped('amount_total_signed')) + elif has_settlement: + total_uang_muka = self.gross_amount + else: + raise UserError( + "Tidak bisa melakukan refund karena SO tidak memiliki Record Uang Masuk " + "(Journal Uang Muka/Midtrans Payment)." + ) invoice_ids = self.invoice_ids.filtered(lambda inv: inv.state != 'cancel') + total_refunded = sum(self.refund_ids.mapped('amount_refund')) + sisa_uang_muka = total_uang_muka - total_refunded + + if sisa_uang_muka <= 0: + raise UserError("❌ Tidak ada sisa transaksi untuk di-refund. Semua dana sudah dikembalikan.") return { 'name': 'Refund Sale Order', 'type': 'ir.actions.act_window', 'res_model': 'refund.sale.order', 'view_mode': 'form', + 'target':'new', 'target': 'current', 'context': { 'default_sale_order_ids': [(6, 0, [self.id])], 'default_invoice_ids': [(6, 0, invoice_ids.ids)], - 'default_uang_masuk': sum(invoice_ids.mapped('amount_total')) + (self.delivery_amt or 0.0) + 1000, + 'default_uang_masuk': sisa_uang_muka, 'default_ongkir': self.delivery_amt or 0.0, - 'default_bank': '', # bisa isi default bank kalau mau + 'default_bank': '', 'default_account_name': '', 'default_account_no': '', 'default_refund_type': '', @@ -3308,6 +3320,30 @@ class SaleOrder(models.Model): if not self: raise UserError("Tidak ada Sale Order yang dipilih.") + if len(self) > 1: + not_cancel_orders = self.filtered(lambda so: so.state != 'cancel') + if not_cancel_orders: + raise ValidationError( + f"❌ Refund Multi SO hanya bisa dibuat untuk SO dengan status Cancel. " + f"SO berikut tidak Cancel: {', '.join(not_cancel_orders.mapped('name'))}" + ) + + + invalid_status_orders = [] + for order in self: + if order.state not in ['cancel', 'sale']: + invalid_status_orders.append(order.name) + elif order.state == 'sale': + not_done_pickings = order.picking_ids.filtered(lambda p: p.state != 'done') + if not_done_pickings: + invalid_status_orders.append(order.name) + + if invalid_status_orders: + raise ValidationError( + f"❌ Refund tidak bisa dibuat untuk SO {', '.join(invalid_status_orders)}. " + f"SO harus Cancel atau Sale dengan semua Pengiriman sudah selesai." + ) + partner_set = set(self.mapped('partner_id.id')) if len(partner_set) > 1: raise UserError("Tidak dapat membuat refund untuk Multi SO dengan Customer berbeda. Harus memiliki Customer yang sama.") @@ -3316,14 +3352,43 @@ class SaleOrder(models.Model): if len(invoice_status_set) > 1: raise UserError("Tidak dapat membuat refund untuk SO dengan status invoice berbeda. Harus memiliki status invoice yang sama.") - already_refunded = self.filtered(lambda so: so.has_refund) - if already_refunded: - so_names = ', '.join(already_refunded.mapped('name')) - raise UserError(f"❌ Tidak bisa refund ulang. {so_names} sudah melakukan refund.") + refunded_orders = self.filtered(lambda so: self.env['refund.sale.order'].search([('sale_order_ids', 'in', so.id)], limit=1)) + if refunded_orders: + raise ValidationError( + f"SO {', '.join(refunded_orders.mapped('name'))} sudah pernah di-refund dan tidak bisa ikut dalam refund Multi SO." + ) + + total_uang_masuk = 0.0 + invalid_orders=[] + for order in self: + moves = self.env['account.move'].search([ + ('sale_id', '=', order.id), + ('journal_id', '=', 11), + ('state', '=', 'posted'), + ]) + + total_uang_muka = 0.0 + + if moves and order.payment_status == 'settlement': + total_uang_muka = order.gross_amount + sum(moves.mapped('amount_total_signed')) or 0.0 + elif moves: + total_uang_muka = sum(moves.mapped('amount_total_signed')) or 0.0 + elif order.payment_status == 'settlement': + total_uang_muka = order.gross_amount + else: + invalid_orders.append(order.name) + + total_uang_masuk += total_uang_muka + + if invalid_orders: + raise ValidationError( + f"Tidak dapat membuat refund untuk SO {', '.join(invalid_orders)} karena tidak memiliki Record Uang Masuk (Journal Uang Muka/Midtrans).\n" + "Pastikan semua SO yang dipilih sudah memiliki Record pembayaran yang valid." + ) + invoice_ids = self.mapped('invoice_ids').filtered(lambda inv: inv.state != 'cancel') delivery_total = sum(self.mapped('delivery_amt')) - total_invoice = sum(invoice_ids.mapped('amount_total')) return { 'type': 'ir.actions.act_window', @@ -3334,7 +3399,7 @@ class SaleOrder(models.Model): 'context': { 'default_sale_order_ids': [(6, 0, self.ids)], 'default_invoice_ids': [(6, 0, invoice_ids.ids)], - 'default_uang_masuk': total_invoice + delivery_total + 1000, + 'default_uang_masuk': total_uang_masuk, 'default_ongkir': delivery_total, 'default_bank': '', 'default_account_name': '', @@ -3343,11 +3408,6 @@ class SaleOrder(models.Model): } } - @api.depends('refund_ids') - def _compute_has_refund(self): - for so in self: - so.has_refund = bool(so.refund_ids) - def action_view_related_refunds(self): self.ensure_one() return { |
