summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndriFP <113114423+andrifp@users.noreply.github.com>2025-09-12 17:34:56 +0700
committerAndriFP <113114423+andrifp@users.noreply.github.com>2025-09-12 17:34:56 +0700
commite79284c1d0e8b364438163847491d51e450fcaa2 (patch)
tree9a9775a387685a7ee560e2e7b614fb25071ec4df
parentf2b1b0ec605b552c2bf225de46094cd4707197ee (diff)
parent7973c3153f852f154c04e1107206ebe90498e771 (diff)
Merge branch 'odoo-backup' of https://bitbucket.org/altafixco/indoteknik-addons into form-sp
-rw-r--r--indoteknik_api/controllers/api_v1/user.py3
-rw-r--r--indoteknik_custom/models/account_move.py28
-rw-r--r--indoteknik_custom/models/approval_payment_term.py10
-rw-r--r--indoteknik_custom/models/dunning_run.py3
-rw-r--r--indoteknik_custom/models/refund_sale_order.py28
-rw-r--r--indoteknik_custom/models/res_partner.py11
-rwxr-xr-xindoteknik_custom/models/sale_order.py129
-rw-r--r--indoteknik_custom/models/sale_order_line.py6
-rw-r--r--indoteknik_custom/models/stock_move.py3
-rw-r--r--indoteknik_custom/models/tukar_guling.py4
-rw-r--r--indoteknik_custom/report/purchase_report.xml171
-rw-r--r--indoteknik_custom/views/account_move.xml1
-rw-r--r--indoteknik_custom/views/approval_payment_term.xml2
-rw-r--r--indoteknik_custom/views/dunning_run.xml5
-rw-r--r--indoteknik_custom/views/res_partner.xml13
-rwxr-xr-xindoteknik_custom/views/sale_order.xml15
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"/>