diff options
| author | AndriFP <113114423+andrifp@users.noreply.github.com> | 2025-09-12 17:34:56 +0700 |
|---|---|---|
| committer | AndriFP <113114423+andrifp@users.noreply.github.com> | 2025-09-12 17:34:56 +0700 |
| commit | e79284c1d0e8b364438163847491d51e450fcaa2 (patch) | |
| tree | 9a9775a387685a7ee560e2e7b614fb25071ec4df | |
| parent | f2b1b0ec605b552c2bf225de46094cd4707197ee (diff) | |
| parent | 7973c3153f852f154c04e1107206ebe90498e771 (diff) | |
Merge branch 'odoo-backup' of https://bitbucket.org/altafixco/indoteknik-addons into form-sp
| -rw-r--r-- | indoteknik_api/controllers/api_v1/user.py | 3 | ||||
| -rw-r--r-- | indoteknik_custom/models/account_move.py | 28 | ||||
| -rw-r--r-- | indoteknik_custom/models/approval_payment_term.py | 10 | ||||
| -rw-r--r-- | indoteknik_custom/models/dunning_run.py | 3 | ||||
| -rw-r--r-- | indoteknik_custom/models/refund_sale_order.py | 28 | ||||
| -rw-r--r-- | indoteknik_custom/models/res_partner.py | 11 | ||||
| -rwxr-xr-x | indoteknik_custom/models/sale_order.py | 129 | ||||
| -rw-r--r-- | indoteknik_custom/models/sale_order_line.py | 6 | ||||
| -rw-r--r-- | indoteknik_custom/models/stock_move.py | 3 | ||||
| -rw-r--r-- | indoteknik_custom/models/tukar_guling.py | 4 | ||||
| -rw-r--r-- | indoteknik_custom/report/purchase_report.xml | 171 | ||||
| -rw-r--r-- | indoteknik_custom/views/account_move.xml | 1 | ||||
| -rw-r--r-- | indoteknik_custom/views/approval_payment_term.xml | 2 | ||||
| -rw-r--r-- | indoteknik_custom/views/dunning_run.xml | 5 | ||||
| -rw-r--r-- | indoteknik_custom/views/res_partner.xml | 13 | ||||
| -rwxr-xr-x | indoteknik_custom/views/sale_order.xml | 15 |
16 files changed, 224 insertions, 208 deletions
diff --git a/indoteknik_api/controllers/api_v1/user.py b/indoteknik_api/controllers/api_v1/user.py index c75e4954..3511bc52 100644 --- a/indoteknik_api/controllers/api_v1/user.py +++ b/indoteknik_api/controllers/api_v1/user.py @@ -90,7 +90,8 @@ class User(controller.Controller): 'login': email, 'oauth_provider_id': request.env.ref('auth_oauth.provider_google').id, 'sel_groups_1_9_10': 9, - 'active': True + 'active': True, + } user = request.env['res.users'].create(user_data) diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py index 764a8b20..4fb3db22 100644 --- a/indoteknik_custom/models/account_move.py +++ b/indoteknik_custom/models/account_move.py @@ -105,6 +105,34 @@ class AccountMove(models.Model): tracking=True ) + # def _check_and_lock_cbd(self): + # cbd_term = self.env['account.payment.term'].browse(26) + # today = date.today() + + # # Cari semua invoice overdue + # overdue_invoices = self.search([ + # ('move_type', '=', 'out_invoice'), + # ('state', '=', 'posted'), + # ('payment_state', 'not in', ['paid', 'in_payment', 'reversed']), + # ('invoice_date_due', '!=', False), + # ('invoice_date_due', '<=', today - timedelta(days=30)), + # ], limit=3) + + # _logger.info(f"Found {len(overdue_invoices)} overdue invoices for CBD lock check.") + # _logger.info(f"Overdue Invoices: {overdue_invoices.mapped('name')}") + + # # Ambil partner unik dari invoice + # partners_to_lock = overdue_invoices.mapped('partner_id').filtered(lambda p: not p.is_cbd_locked) + # _logger.info(f"Partners to lock: {partners_to_lock.mapped('name')}") + + # # Lock hanya partner yang belum locked + # if partners_to_lock: + # partners_to_lock.write({ + # 'is_cbd_locked': True, + # 'property_payment_term_id': cbd_term.id, + # }) + + def compute_partial_payment(self): for move in self: if move.amount_total_signed > 0 and move.amount_residual_signed > 0 and move.payment_state == 'partial': diff --git a/indoteknik_custom/models/approval_payment_term.py b/indoteknik_custom/models/approval_payment_term.py index 8618856a..7cab91f1 100644 --- a/indoteknik_custom/models/approval_payment_term.py +++ b/indoteknik_custom/models/approval_payment_term.py @@ -69,8 +69,8 @@ class ApprovalPaymentTerm(models.Model): return res def _track_changes_for_user_688(self, vals, old_values_dict): - if self.env.user.id != 688: - return + # if self.env.user.id != 688: + # return tracked_fields = {"blocking_stage", "warning_stage", "property_payment_term_id"} @@ -106,7 +106,8 @@ class ApprovalPaymentTerm(models.Model): if changes: timestamp = fields.Datetime.now().strftime('%Y-%m-%d %H:%M:%S') - rec.change_log_688 = f"{timestamp} - Perubahan oleh Widya:\n" + "\n".join(changes) + user = self.env.user + rec.change_log_688 = f"{timestamp} - Perubahan oleh {user.name}:\n" + "\n".join(changes) @staticmethod @@ -171,7 +172,8 @@ class ApprovalPaymentTerm(models.Model): 'blocking_stage': self.blocking_stage, 'warning_stage': self.warning_stage, 'active_limit': self.active_limit, - 'property_payment_term_id': self.property_payment_term_id.id + 'property_payment_term_id': self.property_payment_term_id.id, + 'is_locked_cbd': False, }) self.approve_date = datetime.utcnow() self.state = 'approved' diff --git a/indoteknik_custom/models/dunning_run.py b/indoteknik_custom/models/dunning_run.py index 5a6aebac..9feea1d1 100644 --- a/indoteknik_custom/models/dunning_run.py +++ b/indoteknik_custom/models/dunning_run.py @@ -1,6 +1,6 @@ from odoo import models, api, fields from odoo.exceptions import AccessError, UserError, ValidationError -from datetime import timedelta +from datetime import timedelta, date import logging @@ -149,4 +149,5 @@ class DunningRunLine(models.Model): total_amt = fields.Float(string='Total Amount') open_amt = fields.Float(string='Open Amount') due_date = fields.Date(string='Due Date') + payment_term = fields.Many2one('account.payment.term', related='invoice_id.invoice_payment_term_id', string='Payment Term') diff --git a/indoteknik_custom/models/refund_sale_order.py b/indoteknik_custom/models/refund_sale_order.py index 9ab18f27..f511ed5d 100644 --- a/indoteknik_custom/models/refund_sale_order.py +++ b/indoteknik_custom/models/refund_sale_order.py @@ -463,7 +463,7 @@ class RefundSaleOrder(models.Model): total_invoice = 0.0 so_ids = self.sale_order_ids.ids - + amount_refund_before = 0.0 for so in self.sale_order_ids: self.ongkir += so.delivery_amt or 0.0 valid_invoices = so.invoice_ids.filtered( @@ -471,6 +471,10 @@ class RefundSaleOrder(models.Model): ) all_invoices |= valid_invoices total_invoice += sum(valid_invoices.mapped('amount_total_signed')) + refunds = self.env['refund.sale.order'].search([ + ('sale_order_ids', 'in', so_ids) + ]) + amount_refund_before += sum(refunds.mapped('amount_refund')) if refunds else 0.0 moves = self.env['account.move'].search([ ('sale_id', 'in', so_ids), @@ -479,7 +483,7 @@ class RefundSaleOrder(models.Model): ]) total_uang_muka = sum(moves.mapped('amount_total_signed')) if moves else 0.0 total_midtrans = sum(self.env['sale.order'].browse(so_ids).mapped('gross_amount')) if so_ids else 0.0 - self.uang_masuk = total_uang_muka + total_midtrans + self.uang_masuk = (total_uang_muka + total_midtrans) - amount_refund_before self.invoice_ids = all_invoices @@ -820,15 +824,26 @@ class RefundSaleOrder(models.Model): # Ambil label refund type refund_type_label = dict( self.fields_get(allfields=['refund_type'])['refund_type']['selection'] - ).get(refund.refund_type, '').replace("Refund ", "").upper() - + ).get(refund.refund_type, '') + + # Normalisasi + refund_type_label = refund_type_label.upper() + + if refund.refund_type in ['barang_kosong', 'barang_kosong_sebagian']: + refund_type_label = "REFUND BARANG KOSONG" + elif refund.refund_type in ['retur_half', 'retur']: + refund_type_label = "REFUND RETUR BARANG" + elif refund.refund_type == 'uang': + refund_type_label = "REFUND LEBIH BAYAR" + elif refund.refund_type == 'salah_transfer': + refund_type_label = "REFUND SALAH TRANSFER" if not partner: raise UserError("❌ Partner tidak ditemukan.") # Ref format - ref_text = f"REFUND {refund_type_label} {refund.name or ''} {partner.display_name}".upper() + ref_text = f"{refund_type_label} {refund.name or ''} {partner.display_name}".upper() # Buat Account Move (Journal Entry) account_move = self.env['account.move'].create({ @@ -878,7 +893,8 @@ class RefundSaleOrder(models.Model): def _compute_journal_refund_move_id(self): for rec in self: move = self.env['account.move'].search([ - ('refund_id', '=', rec.id) + ('refund_id', '=', rec.id), + ('state', '!=', 'cancel') ], limit=1) rec.journal_refund_move_id = move diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py index 148a3fd0..36570e8f 100644 --- a/indoteknik_custom/models/res_partner.py +++ b/indoteknik_custom/models/res_partner.py @@ -1,6 +1,6 @@ from odoo import models, fields, api from odoo.exceptions import UserError, ValidationError -from datetime import datetime +from datetime import datetime, timedelta from odoo.http import request import re import requests @@ -181,10 +181,8 @@ class ResPartner(models.Model): payment_difficulty = fields.Selection([('bermasalah', 'Bermasalah'),('sulit', 'Sulit'),('agak_sulit', 'Agak Sulit'),('normal', 'Normal')], string='Payment Difficulty', tracking=3) payment_history_url = fields.Text(string='Payment History URL') - # no compute - # payment_diff = fields.Selection([('bermasalah', 'Bermasalah'),('sulit', 'Sulit'),('agak_sulit', 'Agak Sulit'),('normal', 'Normal')], string='Payment Difficulty', tracking=3) - - # tidak terpakai + is_cbd_locked = fields.Boolean("Locked to CBD?", default=False, tracking=True, help="Jika dicentang, maka partner ini terkunci pada payment term CBD karena memiliki invoice yang sudah jatuh tempo lebih dari 30 hari.") + @api.model def _default_payment_term(self): @@ -193,9 +191,10 @@ class ResPartner(models.Model): property_payment_term_id = fields.Many2one( 'account.payment.term', string='Payment Terms', - default=_default_payment_term + default=_default_payment_term, tracking=3 ) + @api.depends("street", "street2", "city", "state_id", "country_id", "blok", "nomor", "rt", "rw", "kelurahan_id", "kecamatan_id") def _alamat_lengkap_text(self): diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 9952af9a..c767dd04 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) @@ -393,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): @@ -2029,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 @@ -2115,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: @@ -2137,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() @@ -2191,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() @@ -2460,6 +2486,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() @@ -2645,23 +2672,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) @@ -3103,52 +3124,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): diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py index 47a24264..1f2ea1fb 100644 --- a/indoteknik_custom/models/sale_order_line.py +++ b/indoteknik_custom/models/sale_order_line.py @@ -71,23 +71,17 @@ class SaleOrderLine(models.Model): if order_qty > 0: for move in line.move_ids: - # --- CASE 1: Move belum selesai --- if move.state not in ('done', 'cancel'): reserved_qty += move.reserved_availability or 0.0 continue - # --- CASE 2: Move sudah done --- if move.location_dest_id.usage == 'customer': - # Barang dikirim ke customer delivered_qty += move.quantity_done or 0.0 elif move.location_id.usage == 'customer': - # Barang balik dari customer (retur) delivered_qty -= move.quantity_done or 0.0 - # Clamp supaya delivered gak minus delivered_qty = max(delivered_qty, 0) - # Hitung persen line.reserved_percent = min((reserved_qty / order_qty) * 100, 100) if order_qty else 0 line.delivered_percent = min((delivered_qty / order_qty) * 100, 100) if order_qty else 0 line.unreserved_percent = max(100 - line.reserved_percent - line.delivered_percent, 0) diff --git a/indoteknik_custom/models/stock_move.py b/indoteknik_custom/models/stock_move.py index 24d405a6..d6505a86 100644 --- a/indoteknik_custom/models/stock_move.py +++ b/indoteknik_custom/models/stock_move.py @@ -18,7 +18,8 @@ class StockMove(models.Model): 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) - product_image = fields.Binary(related="product_id.image_128", string="Product Image", readonly = True) + product_image = fields.Binary(related="product_id.image_128", string="Product Image", readonly=True) + # @api.model_create_multi # def create(self, vals_list): # moves = super(StockMove, self).create(vals_list) diff --git a/indoteknik_custom/models/tukar_guling.py b/indoteknik_custom/models/tukar_guling.py index 6e839bf0..d718ba0f 100644 --- a/indoteknik_custom/models/tukar_guling.py +++ b/indoteknik_custom/models/tukar_guling.py @@ -710,7 +710,7 @@ class TukarGuling(models.Model): ### ======== SRT dari BU/OUT ========= srt_return_lines = [] - if mapping_koli: + if mapping_koli and record.operations.picking_type_id.id == 29: for prod in mapping_koli.mapped('product_id'): qty_total = sum(mk.qty_return for mk in mapping_koli.filtered(lambda m: m.product_id == prod)) move = bu_out.move_lines.filtered(lambda m: m.product_id == prod) @@ -723,7 +723,7 @@ class TukarGuling(models.Model): })) _logger.info(f"📟 SRT line: {prod.display_name} | qty={qty_total}") - elif not mapping_koli: + elif not mapping_koli and record.operations.picking_type_id.id == 29: for line in record.line_ids: move = bu_out.move_lines.filtered(lambda m: m.product_id == line.product_id) if not move: diff --git a/indoteknik_custom/report/purchase_report.xml b/indoteknik_custom/report/purchase_report.xml index 9d7f4028..cd8af78a 100644 --- a/indoteknik_custom/report/purchase_report.xml +++ b/indoteknik_custom/report/purchase_report.xml @@ -25,96 +25,88 @@ </t> </template> - <!-- Document Template --> -<template id="report_purchaseorder_website_document"> - <t t-call="web.external_layout"> + <template id="report_purchaseorder_website_document"> + <t t-call="web.html_container"> <t t-set="doc" t-value="doc.with_context(lang=doc.partner_id.lang)" /> - <div class="page"> - <!-- Header Image --> - <div class="mb16"> - <img src="https://erp.indoteknik.com/api/image/ir.attachment/datas/2498521" - style="width:100%; max-height:100px; object-fit:contain;"/> - </div> + <!-- Header --> + <div class="header"> + <img src="https://erp.indoteknik.com/api/image/ir.attachment/datas/2498521" + style="width:100%; display: block;"/> + </div> - <!-- Title --> - <h2 class="text-center mb4" style="color:#d32f2f; font-weight:bold;"> + + <!-- PAGE CONTENT --> + <div class="article" style="margin: 0 1.5cm 0 1.5cm; "> + <!-- TITLE --> + <h2 style="text-align:center; margin:0; color:#d32f2f; font-weight:bold;"> PURCHASE ORDER </h2> - <h4 class="text-center mb32"> + <h4 style="text-align:center; margin:0 0 20px 0;"> No. <span t-field="doc.name"/> </h4> - <!-- Top Info sejajar --> - <div class="row mb16" style="font-size:12px;"> - <div class="col-4"> - <strong>Term Of Payment:</strong> - <span t-field="doc.payment_term_id.name"/> - </div> - <div class="col-4"> - <strong>Order Date:</strong> - <span t-field="doc.date_order" t-options='{"widget": "date"}'/> - </div> - <div class="col-4"> - <strong>Responsible:</strong> - <span t-field="doc.user_id"/> - </div> - </div> + <!-- TOP INFO --> + <table style="width:100%; margin-bottom:16px; font-size:14px;"> + <tr> + <td><strong>Term Of Payment:</strong> <span t-field="doc.payment_term_id.name"/></td> + <td><strong>Order Date:</strong> <span t-field="doc.date_order" t-options='{"widget": "date"}'/></td> + <td><strong>Responsible:</strong> <span t-field="doc.user_id"/></td> + </tr> + </table> - <!-- Vendor & Shipping Info sejajar --> - <div class="row mb32" style="font-size:12px;"> - <div class="col-6" style="border:1px solid #ccc; padding:8px;"> - <strong>Alamat Pengiriman:</strong><br/> - PT Indoteknik (Bandengan 1 Depan)<br/> - Jl. Bandengan Utara Komp A 8 B<br/> - RT. Penjaringan, Kec. Penjaringan, Jakarta (BELAKANG INDOMARET)<br/> - JK 14440<br/> - Indonesia - </div> - <div class="col-6" style="border:1px solid #ccc; padding:8px;"> - <strong>Nama Vendor:</strong><br/> - <div t-field="doc.partner_id" - t-options='{"widget": "contact", "fields": ["address", "name", "phone"], - "no_marker": True, "phone_icons": True}'/> - </div> - </div> + <!-- VENDOR & DELIVERY --> + <table style="width:100%; margin-bottom:24px; border-collapse:separate; border-spacing:16px 0;"> + <tr> + <td style="width:50%; border:1px solid #ccc; padding:8px; vertical-align:top;"> + <strong>Alamat Pengiriman:</strong><br/> + PT Indoteknik (Bandengan 1 Depan)<br/> + Jl. Bandengan Utara Komp A 8 B<br/> + RT. Penjaringan, Kec. Penjaringan, Jakarta (BELAKANG INDOMARET)<br/> + JK 14440 - Indonesia + </td> + <td style="width:50%; border:1px solid #ccc; padding:8px; vertical-align:top;"> + <strong>Nama Vendor:</strong><br/> + <span t-field="doc.partner_id.name"/><br/> + <span t-field="doc.partner_id.street"/><br/> + <span t-field="doc.partner_id.city"/> - <span t-field="doc.partner_id.zip"/> + </td> + </tr> + </table> - <!-- Order Lines --> - <table class="table table-sm o_main_table" style="font-size:11px; border:1px solid #000; border-collapse: collapse; width:100%;"> - <thead style="display: table-row-group; background:#f5f5f5;"> - <tr> - <th style="border:1px solid #000; padding:4px;">Description</th> - <th class="text-right" style="border:1px solid #000; padding:4px;">Quantity</th> - <th class="text-right" style="border:1px solid #000; padding:4px;">Unit Price</th> - <th class="text-right" style="border:1px solid #000; padding:4px;">Taxes</th> - <th class="text-right" style="border:1px solid #000; padding:4px;">Subtotal</th> + <!-- ORDER LINES --> + <table style="border-collapse:collapse; width:100%; margin-top:16px;"> + <thead> + <tr style="background:#f2f2f2;"> + <th style="border:1px solid #ccc; padding:4px;">Description</th> + <th style="border:1px solid #ccc; padding:4px; text-align:right;">Quantity</th> + <th style="border:1px solid #ccc; padding:4px; text-align:right;">Unit Price</th> + <th style="border:1px solid #ccc; padding:4px; text-align:right;">Taxes</th> + <th style="border:1px solid #ccc; padding:4px; text-align:right;">Subtotal</th> </tr> </thead> <tbody> <t t-foreach="doc.order_line" t-as="line"> - <!-- Main row --> <tr> - <td style="border:1px solid #000; padding:4px;"> + <td style="border:1px solid #ccc; padding:4px;"> <span t-field="line.name"/> </td> - <td class="text-right" style="border:1px solid #000; padding:4px;"> - <span t-field="line.product_qty"/> - <span t-field="line.product_uom"/> + <td style="border:1px solid #ccc; padding:4px; text-align:right;"> + <span t-field="line.product_qty"/> <span t-field="line.product_uom"/> </td> - <td class="text-right" style="border:1px solid #000; padding:4px;"> + <td style="border:1px solid #ccc; padding:4px; text-align:right;"> <span t-field="line.price_unit"/> </td> - <td class="text-right" style="border:1px solid #000; padding:4px;"> + <td style="border:1px solid #ccc; padding:4px; text-align:right;"> <span t-esc="', '.join(map(lambda x: (x.description or x.name), line.taxes_id))"/> </td> - <td class="text-right" style="border:1px solid #000; padding:4px;"> + <td style="border:1px solid #ccc; padding:4px; text-align:right;"> <span t-field="line.price_subtotal"/> </td> </tr> - <!-- Website Description row --> <t t-if="line.product_id.website_description"> <tr> - <td colspan="5" style="border:1px solid #000; padding:6px; font-size:10px; color:#555;"> + <td colspan="5" style="padding:8px 12px; font-size:11px; background:#fafafa; border-left:1px solid #ccc; border-right:1px solid #ccc;"> <div t-raw="line.product_id.website_description"/> </td> </tr> @@ -123,40 +115,35 @@ </tbody> </table> - <!-- Totals --> - <div class="clearfix"> - <div class="row"> - <div class="col-4 ml-auto"> - <table class="table table-sm" style="border:1px solid #000; border-collapse: collapse; width:100%;"> - <tr> - <td style="border:1px solid #000; padding:4px;"><strong>Subtotal</strong></td> - <td class="text-right" style="border:1px solid #000; padding:4px;"> - <span t-field="doc.amount_untaxed"/> - </td> - </tr> - <tr> - <td style="border:1px solid #000; padding:4px;">Taxes</td> - <td class="text-right" style="border:1px solid #000; padding:4px;"> - <span t-field="doc.amount_tax"/> - </td> - </tr> - <tr class="o_total"> - <td style="border:1px solid #000; padding:4px;"><strong>Total</strong></td> - <td class="text-right" style="border:1px solid #000; padding:4px;"> - <span t-field="doc.amount_total"/> - </td> - </tr> - </table> - </div> - </div> - </div> + <!-- TOTALS --> + <table style="margin-top:20px; margin-left:auto; width:40%; font-size:14px;"> + <tr> + <td><strong>Subtotal</strong></td> + <td style="text-align:right;"><span t-field="doc.amount_untaxed"/></td> + </tr> + <tr> + <td>Taxes</td> + <td style="text-align:right;"><span t-field="doc.amount_tax"/></td> + </tr> + <tr> + <td><strong>Total</strong></td> + <td style="text-align:right;"><span t-field="doc.amount_total"/></td> + </tr> + </table> - <!-- Notes --> - <div class="mt32" style="font-size:11px;"> + <!-- NOTES --> + <div style="margin-top:24px;"> <p t-field="doc.notes"/> </div> </div> + <!-- STATIC FOOTER --> + <div class="footer"> + <img src="https://erp.indoteknik.com/api/image/ir.attachment/datas/2859765" + style="width:100%; display: block;"/> + </div> + </t> </template> + </odoo> diff --git a/indoteknik_custom/views/account_move.xml b/indoteknik_custom/views/account_move.xml index 1b477c6d..c88effd5 100644 --- a/indoteknik_custom/views/account_move.xml +++ b/indoteknik_custom/views/account_move.xml @@ -39,6 +39,7 @@ </field> <field name="ref" position="after"> <field name="sale_id" readonly="1" attrs="{'invisible': ['|', ('move_type', '!=', 'entry'), ('has_refund_so', '=', True)]}"/> + <field name="refund_id" readonly="1" attrs="{'invisible': ['|', ('move_type', '!=', 'entry'), ('has_refund_so', '=', False)]}"/> <field name="refund_so_links" readonly="1" widget="html" attrs="{'invisible': ['|', ('move_type', '!=', 'entry'), ('has_refund_so', '=', False)]}"/> <field name="has_refund_so" invisible="1"/> </field> diff --git a/indoteknik_custom/views/approval_payment_term.xml b/indoteknik_custom/views/approval_payment_term.xml index 5c130f3f..b0b99689 100644 --- a/indoteknik_custom/views/approval_payment_term.xml +++ b/indoteknik_custom/views/approval_payment_term.xml @@ -7,7 +7,7 @@ <tree default_order="create_date desc"> <field name="number"/> <field name="partner_id"/> - <field name="parent_id"/> + <field name="parent_id" optional="hide"/> <field name="property_payment_term_id"/> <field name="create_date" optional="hide"/> <field name="approve_date" optional="hide"/> diff --git a/indoteknik_custom/views/dunning_run.xml b/indoteknik_custom/views/dunning_run.xml index f624c42e..51377f78 100644 --- a/indoteknik_custom/views/dunning_run.xml +++ b/indoteknik_custom/views/dunning_run.xml @@ -25,13 +25,14 @@ <field name="arch" type="xml"> <tree> <field name="partner_id"/> + <field name="reference"/> <field name="invoice_id"/> <field name="date_invoice"/> - <field name="efaktur_id"/> - <field name="reference"/> + <field name="efaktur_id" optional="hide"/> <field name="total_amt" sum="Grand Total Amount"/> <field name="open_amt"/> <field name="due_date"/> + <field name="payment_term"/> </tree> </field> </record> diff --git a/indoteknik_custom/views/res_partner.xml b/indoteknik_custom/views/res_partner.xml index ca1a36de..c32151d8 100644 --- a/indoteknik_custom/views/res_partner.xml +++ b/indoteknik_custom/views/res_partner.xml @@ -21,6 +21,7 @@ <field name="reference_number"/> </field> <field name="property_payment_term_id" position="after"> + <field name="is_cbd_locked" readonly="1"/> <field name="user_payment_terms_sales" readonly="1"/> <field name="date_payment_terms_sales" readonly="1"/> </field> @@ -35,9 +36,9 @@ <field name="pareto_status"/> <field name="digital_invoice_tax"/> </field> - <field name="nama_wajib_pajak" position="attributes"> + <!-- <field name="nama_wajib_pajak" position="attributes"> <attribute name="required">1</attribute> - </field> + </field> --> <field name="kota_id" position="attributes"> <attribute name="required">0</attribute> </field> @@ -47,14 +48,14 @@ <field name="kelurahan_id" position="attributes"> <attribute name="required">0</attribute> </field> - <field name="npwp" position="attributes"> + <!-- <field name="npwp" position="attributes"> <attribute name="required">1</attribute> </field> <field name="alamat_lengkap_text" position="attributes"> <attribute name="required">1</attribute> - </field> + </field> --> <field name="npwp" position="before"> - <field name="customer_type" required="1"/> + <field name="customer_type"/> </field> <field name="alamat_lengkap_text" position="after"> <field name="nitku" /> @@ -107,7 +108,7 @@ <field name="reminder_invoices"/> </xpath> <xpath expr="//field[@name='property_payment_term_id']" position="attributes"> - <attribute name="readonly">0</attribute> + <attribute name="readonly">1</attribute> </xpath> <xpath expr="//field[@name='property_supplier_payment_term_id']" position="attributes"> <attribute name="readonly">1</attribute> diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index 156c48d7..44da3e13 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -41,6 +41,15 @@ string="Refund" class="btn-primary" /> </xpath> + <xpath expr="//sheet" position="before"> + <field name="partner_is_cbd_locked" invisible="1"/> + <div class="alert alert-danger" + role="alert" + style="height: 40px; margin-bottom:0px;" + attrs="{'invisible':['|', ('partner_is_cbd_locked','=',False), ('state', 'not in', ['draft', 'cancel'])]}"> + <strong>Warning!</strong> Payment Terms Customer terkunci menjadi <b>Cash Before Delivery (C.B.D.)</b> karena ada invoice telah jatuh tempo <b>30 hari</b>. Silakan ajukan <b>Approval Payment Term</b> untuk membuka kunci. + </div> + </xpath> <div class="oe_button_box" name="button_box"> <field name="advance_payment_move_ids" invisible="1"/> <button name="action_open_advance_payment_moves" @@ -139,9 +148,9 @@ <field name="pareto_status"/> </field> <field name="analytic_account_id" position="after"> - <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="customer_type"/> + <field name="npwp" placeholder='99.999.999.9-999.999'/> + <field name="sppkp" attrs="{'required': [('customer_type', '=', 'pkp')]}"/> <field name="email" required="1"/> <field name="unreserve_id"/> <field name="due_id" readonly="1"/> |
