summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indoteknik_api/controllers/api_v1/stock_picking.py9
-rwxr-xr-xindoteknik_custom/__manifest__.py1
-rwxr-xr-xindoteknik_custom/models/__init__.py1
-rw-r--r--indoteknik_custom/models/approval_date_doc.py9
-rw-r--r--indoteknik_custom/models/approval_invoice_date.py46
-rw-r--r--indoteknik_custom/models/barcoding_product.py23
-rw-r--r--indoteknik_custom/models/delivery_order.py7
-rw-r--r--indoteknik_custom/models/logbook_sj.py5
-rwxr-xr-xindoteknik_custom/models/product_template.py2
-rwxr-xr-xindoteknik_custom/models/purchase_order.py120
-rw-r--r--indoteknik_custom/models/res_partner.py37
-rwxr-xr-xindoteknik_custom/models/sale_order.py81
-rw-r--r--indoteknik_custom/models/stock_picking.py283
-rw-r--r--indoteknik_custom/models/voucher.py16
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv1
-rw-r--r--indoteknik_custom/views/approval_invoice_date.xml92
-rw-r--r--indoteknik_custom/views/barcoding_product.xml5
-rw-r--r--indoteknik_custom/views/ir_sequence.xml10
-rwxr-xr-xindoteknik_custom/views/product_template.xml2
-rwxr-xr-xindoteknik_custom/views/sale_order.xml705
-rw-r--r--indoteknik_custom/views/stock_picking.xml12
-rw-r--r--indoteknik_custom/views/vendor_payment_term.xml4
22 files changed, 1106 insertions, 365 deletions
diff --git a/indoteknik_api/controllers/api_v1/stock_picking.py b/indoteknik_api/controllers/api_v1/stock_picking.py
index abd78f0e..e16af332 100644
--- a/indoteknik_api/controllers/api_v1/stock_picking.py
+++ b/indoteknik_api/controllers/api_v1/stock_picking.py
@@ -116,10 +116,10 @@ class StockPicking(controller.Controller):
return self.response(picking.get_tracking_detail())
- @http.route(prefix + 'stock-picking/<id>/documentation', auth='public', methods=['PUT', 'OPTIONS'], csrf=False)
+ @http.route(prefix + 'stock-picking/<scanid>/documentation', auth='public', methods=['PUT', 'OPTIONS'], csrf=False)
@controller.Controller.must_authorized()
def write_partner_stock_picking_documentation(self, **kw):
- id = int(kw.get('id', 0))
+ scanid = int(kw.get('scanid', 0))
sj_document = kw.get('sj_document', False)
paket_document = kw.get('paket_document', False)
@@ -128,7 +128,10 @@ class StockPicking(controller.Controller):
'driver_arrival_date': datetime.utcnow(),
}
- picking_data = request.env['stock.picking'].search([('id', '=', id)], limit=1)
+ picking_data = request.env['stock.picking'].search([('id', '=', scanid)], limit=1)
+
+ if not picking_data:
+ picking_data = request.env['stock.picking'].search([('picking_code', '=', scanid)], limit=1)
if not picking_data:
return self.response(code=404, description='picking not found')
diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py
index eb00f527..dec0f26a 100755
--- a/indoteknik_custom/__manifest__.py
+++ b/indoteknik_custom/__manifest__.py
@@ -143,6 +143,7 @@
'views/sale_order_multi_uangmuka_penjualan.xml',
'views/shipment_group.xml',
'views/approval_date_doc.xml',
+ 'views/approval_invoice_date.xml',
'views/partner_payment_term.xml',
'views/vendor_payment_term.xml',
'views/approval_unreserve.xml',
diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py
index 06af8b61..605d1016 100755
--- a/indoteknik_custom/models/__init__.py
+++ b/indoteknik_custom/models/__init__.py
@@ -150,3 +150,4 @@ from . import stock_backorder_confirmation
from . import account_payment_register
from . import stock_inventory
from . import sale_order_delay
+from . import approval_invoice_date
diff --git a/indoteknik_custom/models/approval_date_doc.py b/indoteknik_custom/models/approval_date_doc.py
index 751bae82..1a2749d5 100644
--- a/indoteknik_custom/models/approval_date_doc.py
+++ b/indoteknik_custom/models/approval_date_doc.py
@@ -39,12 +39,15 @@ class ApprovalDateDoc(models.Model):
if not self.env.user.is_accounting:
raise UserError("Hanya Accounting Yang Bisa Approve")
self.check_invoice_so_picking
- self.picking_id.driver_departure_date = self.driver_departure_date
- self.picking_id.date_doc_kirim = self.driver_departure_date
+ # Tambahkan context saat mengupdate date_doc_kirim
+ self.picking_id.with_context(from_button_approve=True).write({
+ 'driver_departure_date': self.driver_departure_date,
+ 'date_doc_kirim': self.driver_departure_date
+ })
self.state = 'done'
self.approve_date = datetime.utcnow()
self.approve_by = self.env.user.id
-
+
def button_cancel(self):
self.state = 'cancel'
diff --git a/indoteknik_custom/models/approval_invoice_date.py b/indoteknik_custom/models/approval_invoice_date.py
new file mode 100644
index 00000000..48546e55
--- /dev/null
+++ b/indoteknik_custom/models/approval_invoice_date.py
@@ -0,0 +1,46 @@
+from odoo import models, api, fields
+from odoo.exceptions import AccessError, UserError, ValidationError
+from datetime import timedelta, date, datetime
+import logging
+
+_logger = logging.getLogger(__name__)
+
+class ApprovalInvoiceDate(models.Model):
+ _name = "approval.invoice.date"
+ _description = "Approval Invoice Date"
+ _rec_name = 'number'
+
+ picking_id = fields.Many2one('stock.picking', string='Picking')
+ number = fields.Char(string='Document No', index=True, copy=False, readonly=True, tracking=True)
+ date_invoice = fields.Datetime(
+ string='Invoice Date',
+ copy=False
+ )
+ date_doc_do = fields.Datetime(
+ string='Tanggal Kirim di SJ',
+ copy=False
+ )
+ state = fields.Selection([('draft', 'Draft'), ('done', 'Done'), ('cancel', 'Cancel')], string='State', default='draft', tracking=True)
+ approve_date = fields.Datetime(string='Approve Date', copy=False)
+ approve_by = fields.Many2one('res.users', string='Approve By', copy=False)
+ sale_id = fields.Many2one('sale.order', string='Sale Order')
+ partner_id = fields.Many2one('res.partner', string='Partner')
+ move_id = fields.Many2one('account.move', string='Invoice')
+ note = fields.Char(string='Note')
+
+ def button_approve(self):
+ if not self.env.user.is_accounting:
+ raise UserError("Hanya Accounting Yang Bisa Approve")
+ self.move_id.invoice_date = self.date_doc_do
+ self.state = 'done'
+ self.approve_date = datetime.utcnow()
+ self.approve_by = self.env.user.id
+
+ def button_cancel(self):
+ self.state = 'cancel'
+
+ @api.model
+ def create(self, vals):
+ vals['number'] = self.env['ir.sequence'].next_by_code('approval.invoice.date') or '0'
+ result = super(ApprovalInvoiceDate, self).create(vals)
+ return result
diff --git a/indoteknik_custom/models/barcoding_product.py b/indoteknik_custom/models/barcoding_product.py
index e1b8f41f..204c6128 100644
--- a/indoteknik_custom/models/barcoding_product.py
+++ b/indoteknik_custom/models/barcoding_product.py
@@ -12,15 +12,32 @@ class BarcodingProduct(models.Model):
barcoding_product_line = fields.One2many('barcoding.product.line', 'barcoding_product_id', string='Barcoding Product Lines', auto_join=True)
product_id = fields.Many2one('product.product', string="Product", tracking=3)
quantity = fields.Float(string="Quantity", tracking=3)
- type = fields.Selection([('print', 'Print Barcode'), ('barcoding', 'Add Barcode To Product')], string='Type', default='print')
+ type = fields.Selection([('print', 'Print Barcode'), ('barcoding', 'Add Barcode To Product'), ('barcoding_box', 'Add Barcode Box To Product')], string='Type', default='print')
barcode = fields.Char(string="Barcode")
+ qty_pcs_box = fields.Char(string="Quantity Pcs Box")
+
+ def check_duplicate_barcode(self):
+ if self.type in ['barcoding_box', 'barcoding']:
+ barcode_product = self.env['product.product'].search([('barcode', '=', self.barcode)])
+
+ if barcode_product:
+ raise UserError('Barcode sudah digunakan {}'.format(barcode_product.display_name))
+
+ barcode_box = self.env['product.product'].search([('barcode_box', '=', self.barcode)])
+
+ if barcode_box:
+ raise UserError('Barcode box sudah digunakan {}'.format(barcode_box.display_name))
@api.constrains('barcode')
def _send_barcode_to_product(self):
for record in self:
- if record.barcode and not record.product_id.barcode:
+ record.check_duplicate_barcode()
+ if record.type == 'barcoding_box':
+ record.product_id.barcode_box = record.barcode
+ record.product_id.qty_pcs_box = record.qty_pcs_box
+ else:
record.product_id.barcode = record.barcode
-
+
@api.onchange('product_id', 'quantity')
def _onchange_product_or_quantity(self):
"""Update barcoding_product_line based on product_id and quantity"""
diff --git a/indoteknik_custom/models/delivery_order.py b/indoteknik_custom/models/delivery_order.py
index 3473197b..2dd0c802 100644
--- a/indoteknik_custom/models/delivery_order.py
+++ b/indoteknik_custom/models/delivery_order.py
@@ -25,7 +25,8 @@ class DeliveryOrder(models.TransientModel):
picking = False
if delivery_order_line[2]['name']:
picking = self.env['stock.picking'].search([('picking_code', '=', delivery_order_line[2]['name'])], limit=1)
-
+ if not picking:
+ picking = self.env['stock.picking'].search([('out_code', '=', delivery_order_line[2]['name'])], limit=1)
if picking:
line_tracking_no = delivery_order_line[2]['tracking_no']
@@ -86,6 +87,10 @@ class DeliveryOrderLine(models.TransientModel):
if len(self.name) == 13:
self.name = self.name[:-1]
picking = self.env['stock.picking'].search([('picking_code', '=', self.name)], limit=1)
+
+ if not picking:
+ picking = self.env['stock.picking'].search([('out_code', '=', self.name)], limit=1)
+
if picking:
if picking.driver_id:
self.driver_id = picking.driver_id
diff --git a/indoteknik_custom/models/logbook_sj.py b/indoteknik_custom/models/logbook_sj.py
index 9f349882..75b2622f 100644
--- a/indoteknik_custom/models/logbook_sj.py
+++ b/indoteknik_custom/models/logbook_sj.py
@@ -26,6 +26,8 @@ class LogbookSJ(models.TransientModel):
report_logbook = self.env['report.logbook.sj'].create([parameters_header])
for line in logbook_line:
picking = self.env['stock.picking'].search([('picking_code', '=', line.name)], limit=1)
+ if not picking:
+ picking = self.env['stock.picking'].search([('out_code', '=', line.name)], limit=1)
stock = picking
parent_id = stock.partner_id.parent_id.id
parent_id = parent_id if parent_id else stock.partner_id.id
@@ -80,6 +82,9 @@ class LogbookSJLine(models.TransientModel):
if len(self.name) == 13:
self.name = self.name[:-1]
picking = self.env['stock.picking'].search([('picking_code', '=', self.name)], limit=1)
+
+ if not picking:
+ picking = self.env['stock.picking'].search([('out_code', '=', self.name)], limit=1)
if picking:
if picking.driver_id:
self.driver_id = picking.driver_id
diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py
index 600dd90e..e6a01a04 100755
--- a/indoteknik_custom/models/product_template.py
+++ b/indoteknik_custom/models/product_template.py
@@ -421,6 +421,8 @@ class ProductProduct(models.Model):
plafon_qty = fields.Float(string='Max Plafon', compute='_get_plafon_qty_product')
merchandise_ok = fields.Boolean(string='Product Promotion')
qr_code_variant = fields.Binary("QR Code Variant", compute='_compute_qr_code_variant')
+ qty_pcs_box = fields.Float("Pcs Box")
+ barcode_box = fields.Char("Barcode Box")
def generate_product_sla(self):
product_variant_ids = self.env.context.get('active_ids', [])
diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py
index b107f389..98b367d0 100755
--- a/indoteknik_custom/models/purchase_order.py
+++ b/indoteknik_custom/models/purchase_order.py
@@ -89,6 +89,112 @@ class PurchaseOrder(models.Model):
store_name = fields.Char(string='Nama Toko')
purchase_order_count = fields.Integer('Purchase Order Count', related='partner_id.purchase_order_count')
+ # cek payment term
+ def _check_payment_term(self):
+ _logger.info("Check Payment Term Terpanggil")
+
+ cbd_term = self.env['account.payment.term'].search([
+ ('name', 'ilike', 'Cash Before Delivery')
+ ], limit=1)
+
+ for order in self:
+ if not order.partner_id or not order.partner_id.minimum_amount:
+ continue
+
+ if not order.order_line or order.amount_total == 0:
+ continue
+
+ if order.amount_total < order.partner_id.minimum_amount:
+ if cbd_term and order.payment_term_id != cbd_term:
+ order.payment_term_id = cbd_term.id
+ self.env.user.notify_info(
+ message="Total belanja PO belum mencapai minimum yang ditentukan vendor. "
+ "Payment Term telah otomatis diubah menjadi Cash Before Delivery (C.B.D).",
+ title="Payment Term Diperbarui"
+ )
+ else:
+ vendor_term = order.partner_id.property_supplier_payment_term_id
+ if vendor_term and order.payment_term_id != vendor_term:
+ order.payment_term_id = vendor_term.id
+ self.env.user.notify_info(
+ message=f"Total belanja PO telah memenuhi jumlah minimum vendor. "
+ f"Payment Term otomatis dikembalikan ke pengaturan vendor awal: *{vendor_term.name}*.",
+ title="Payment Term Diperbarui"
+ )
+
+ def _check_tax_rule(self):
+ _logger.info("Check Tax Rule Terpanggil")
+
+ # Pajak 11%
+ tax_11 = self.env['account.tax'].search([
+ ('type_tax_use', '=', 'purchase'),
+ ('name', 'ilike', '11%')
+ ], limit=1)
+
+ # Pajak "No Tax"
+ no_tax = self.env['account.tax'].search([
+ ('type_tax_use', '=', 'purchase'),
+ ('name', 'ilike', 'no tax')
+ ], limit=1)
+
+ if not tax_11:
+ raise UserError("Pajak 11% tidak ditemukan. Mohon pastikan pajak 11% tersedia.")
+
+ if not no_tax:
+ raise UserError("Pajak 'No Tax' tidak ditemukan. Harap buat tax dengan nama 'No Tax' dan tipe 'Purchase'.")
+
+ for order in self:
+ partner = order.partner_id
+ minimum_tax = partner.minimum_amount_tax
+
+ _logger.info("Partner ID: %s, Minimum Tax: %s, Untaxed Total: %s", partner.id, minimum_tax, order.amount_untaxed)
+
+ if not minimum_tax or not order.order_line:
+ continue
+
+ if order.amount_total < minimum_tax:
+ _logger.info(">>> Total di bawah minimum → apply No Tax")
+ for line in order.order_line:
+ line.taxes_id = [(6, 0, [no_tax.id])]
+
+ if self.env.context.get('notify_tax'):
+ self.env.user.notify_info(
+ message="Total belanja PO belum mencapai minimum pajak vendor. "
+ "Pajak diganti menjadi 'No Tax'.",
+ title="Pajak Diperbarui",
+ )
+ else:
+ _logger.info(">>> Total memenuhi minimum → apply Pajak 11%")
+ for line in order.order_line:
+ line.taxes_id = [(6, 0, [tax_11.id])]
+
+ if self.env.context.get('notify_tax'):
+ self.env.user.notify_info(
+ message="Total belanja sebelum pajak telah memenuhi minimum. "
+ "Pajak 11%% diterapkan",
+ title="Pajak Diperbarui",
+ )
+
+ # set default no_tax pada order line
+ # @api.onchange('order_line')
+ # def _onchange_order_line_tax_default(self):
+ # _logger.info("Onchange Order Line Tax Default Terpanggil")
+
+ # no_tax = self.env['account.tax'].search([
+ # ('type_tax_use', '=', 'purchase'),
+ # ('name', 'ilike', 'no tax')
+ # ], limit=1)
+
+ # if not no_tax:
+ # _logger.info("No Tax tidak ditemukan")
+ # return
+
+ # for order in self:
+ # for line in order.order_line:
+ # if not line.taxes_id:
+ # line.taxes_id = [(6, 0, [no_tax.id])]
+ # _logger.info("Auto-set No tax ke baris product: %s", line.product_id.name)
+
@api.onchange('total_cost_service')
def _onchange_total_cost_service(self):
for order in self:
@@ -672,6 +778,7 @@ class PurchaseOrder(models.Model):
raise UserError("Produk "+line.product_id.name+" memiliki vendor berbeda dengan SO (Vendor PO: "+str(self.partner_id.name)+", Vendor SO: "+str(line.so_line_id.vendor_id.name)+")")
def button_confirm(self):
+ # self._check_payment_term() # check payment term
res = super(PurchaseOrder, self).button_confirm()
current_time = datetime.now()
self.check_ppn_mix()
@@ -1079,6 +1186,19 @@ class PurchaseOrder(models.Model):
return super(PurchaseOrder, self).button_unlock()
+ @api.model #override custom create & write for check payment term
+ def create(self, vals):
+ order = super().create(vals)
+ # order.with_context(skip_check_payment=True)._check_payment_term()
+ # order.with_context(notify_tax=True)._check_tax_rule()
+ return order
+
+ def write(self, vals):
+ res = super().write(vals)
+ if not self.env.context.get('skip_check_payment'):
+ self.with_context(skip_check_payment=True)._check_payment_term()
+ self.with_context(notify_tax=True)._check_tax_rule()
+ return res
class PurchaseOrderUnlockWizard(models.TransientModel):
_name = 'purchase.order.unlock.wizard'
diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py
index fd3a0514..191a44c9 100644
--- a/indoteknik_custom/models/res_partner.py
+++ b/indoteknik_custom/models/res_partner.py
@@ -2,6 +2,7 @@ from odoo import models, fields, api
from odoo.exceptions import UserError, ValidationError
from datetime import datetime
from odoo.http import request
+import re
class GroupPartner(models.Model):
_name = 'group.partner'
@@ -39,6 +40,14 @@ class ResPartner(models.Model):
estimasi_tempo = fields.Char(string='Estimasi Pembelian Pertahun')
tempo_duration = fields.Many2one('account.payment.term', string='Durasi Tempo')
tempo_limit = fields.Char(string='Limit Tempo')
+ minimum_amount = fields.Float(
+ string="Minimum Order",
+ help="Jika total belanja kurang dari ini, maka payment term akan otomatis menjadi CBD."
+ )
+ minimum_amount_tax = fields.Float(
+ string="Minimum Amount Tax",
+ help="Jika total belanja kurang dari ini, maka tax akan otomatis menjadi 0%."
+ )
category_produk_ids = fields.Many2many('product.public.category', string='Kategori Produk yang Digunakan', domain=lambda self: self._get_default_category_domain())
@api.model
@@ -200,6 +209,32 @@ class ResPartner(models.Model):
if existing_partner:
raise ValidationError(f"Nama '{record.name}' sudah digunakan oleh partner lain!")
+ @api.constrains('npwp')
+ def _check_npwp(self):
+ for record in self:
+ npwp = record.npwp.strip() if record.npwp else ''
+ # Abaikan validasi jika NPWP kosong atau diisi "0"
+ if not npwp or npwp == '0' or npwp == '00.000.000.0-000.000':
+ continue
+
+ # Validasi untuk NPWP 15 digit (format: 99.999.999.9-999.999)
+ if len(npwp) == 20:
+ # Regex untuk 15 digit dengan format titik dan tanda hubung
+ pattern_15_digit = r'^\d{2}\.\d{3}\.\d{3}\.\d{1}-\d{3}\.\d{3}$'
+ if not re.match(pattern_15_digit, npwp):
+ raise ValidationError("Format NPWP 15 digit yang dimasukkan salah. Pastikan format yang benar adalah: 99.999.999.9-999.999")
+
+ # Validasi untuk NPWP 16 digit (hanya angka tanpa titik atau tanda hubung)
+ elif len(npwp) == 16:
+ pattern_16_digit = r'^\d{16}$'
+ if not re.match(pattern_16_digit, npwp):
+ raise ValidationError("Format NPWP 16 digit yang dimasukkan salah. Format yang benar adalah 16 digit angka tanpa titik atau tanda hubung.")
+
+ # Validasi panjang NPWP jika lebih atau kurang dari 15 atau 16 digit
+ else:
+ raise ValidationError("Digit NPWP yang dimasukkan tidak sesuai. Pastikan NPWP memiliki 15 digit dengan format tertentu (99.999.999.9-999.999) atau 16 digit tanpa tanda hubung.")
+
+
def write(self, vals):
# Fungsi rekursif untuk meng-update semua child, termasuk child dari child
def update_children_recursively(partner, vals_for_child):
@@ -465,6 +500,8 @@ class ResPartner(models.Model):
def _onchange_customer_type(self):
if self.customer_type == 'nonpkp':
self.npwp = '00.000.000.0-000.000'
+ elif self.customer_type == 'pkp':
+ self.npwp = '00.000.000.0-000.000'
def get_check_payment_term(self):
self.ensure_one()
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index a7ee9db8..3117a330 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -67,6 +67,17 @@ class ShippingOption(models.Model):
class SaleOrder(models.Model):
_inherit = "sale.order"
+ ongkir_ke_xpdc = fields.Float(string='Ongkir ke Ekspedisi', help='Biaya ongkir ekspedisi', copy=False, index=True, tracking=3)
+
+ metode_kirim_ke_xpdc = fields.Selection([
+ ('indoteknik_deliv', 'Indoteknik Delivery'),
+ ('lalamove', 'Lalamove'),
+ ('grab', 'Grab'),
+ ('gojek', 'Gojek'),
+ ('deliveree', 'Deliveree'),
+ ('other', 'Other'),
+ ], string='Metode Kirim Ke Ekspedisi', copy=False, index=True, tracking=3)
+
koli_lines = fields.One2many('sales.order.koli', 'sale_order_id', string='Sales Order Koli', auto_join=True)
fulfillment_line_v2 = fields.One2many('sales.order.fulfillment.v2', 'sale_order_id', string='Fullfillment2')
fullfillment_line = fields.One2many('sales.order.fullfillment', 'sales_order_id', string='Fullfillment')
@@ -315,7 +326,17 @@ class SaleOrder(models.Model):
"sale_order_id": self.id,
})
self.shipping_option_id = shipping_option.id
-
+ self.message_post(
+ body=(
+ f"<b>Estimasi pengiriman Indoteknik berhasil:</b><br/>"
+ f"Layanan: {shipping_option.name}<br/>"
+ f"ETD: {shipping_option.etd}<br/>"
+ f"Biaya: Rp {shipping_option.price:,}<br/>"
+ f"Provider: {shipping_option.provider}"
+ ),
+ message_type="comment",
+ )
+
def action_estimate_shipping(self):
if self.carrier_id.id in [1, 151]:
self.action_indoteknik_estimate_shipping()
@@ -354,6 +375,8 @@ class SaleOrder(models.Model):
shipping_options.append((service, description, etd, value, courier['code']))
self.env["shipping.option"].search([('sale_order_id', '=', self.id)]).unlink()
+
+ _logger.info(f"Shipping options: {shipping_options}")
for service, description, etd, value, provider in shipping_options:
self.env["shipping.option"].create({
@@ -363,12 +386,23 @@ class SaleOrder(models.Model):
"etd": etd,
"sale_order_id": self.id,
})
+
self.shipping_option_id = self.env["shipping.option"].search([('sale_order_id', '=', self.id)], limit=1).id
- self.message_post(body=f"Estimasi Ongkos Kirim: Rp{self.delivery_amt}<br/>Detail Lain:<br/>{'<br/>'.join([f'Service: {s[0]}, Description: {s[1]}, ETD: {s[2]} hari, Cost: Rp {s[3]}' for s in shipping_options])}")
+ _logger.info(f"Shipping option SO ID: {self.shipping_option_id}")
+
+ self.message_post(
+ body=f"Estimasi Ongkos Kirim: Rp{self.delivery_amt}<br/>Detail Lain:<br/>"
+ f"{'<br/>'.join([f'Service: {s[0]}, Description: {s[1]}, ETD: {s[2]} hari, Cost: Rp {s[3]}' for s in shipping_options])}",
+ message_type="comment"
+ )
+
+ # self.message_post(body=f"Estimasi Ongkos Kirim: Rp{self.delivery_amt}<br/>Detail Lain:<br/>{'<br/>'.join([f'Service: {s[0]}, Description: {s[1]}, ETD: {s[2]} hari, Cost: Rp {s[3]}' for s in shipping_options])}", message_type="comment")
+
else:
raise UserError("Gagal mendapatkan estimasi ongkir.")
+
def _call_rajaongkir_api(self, total_weight, destination_subsdistrict_id):
url = 'https://pro.rajaongkir.com/api/cost'
@@ -472,7 +506,7 @@ class SaleOrder(models.Model):
def _compute_date_kirim(self):
for rec in self:
- picking = self.env['stock.picking'].search([('sale_id', '=', rec.id), ('state', 'not in', ['cancel'])], order='date_doc_kirim desc', limit=1)
+ picking = self.env['stock.picking'].search([('sale_id', '=', rec.id), ('state', 'not in', ['cancel']), ('name', 'not ilike', 'BU/PICK/%')], order='date_doc_kirim desc', limit=1)
rec.date_kirim_ril = picking.date_doc_kirim
rec.date_status_done = picking.date_done
rec.date_driver_arrival = picking.driver_arrival_date
@@ -683,12 +717,30 @@ class SaleOrder(models.Model):
# @api.constrains('delivery_amt', 'carrier_id', 'shipping_cost_covered')
def _validate_delivery_amt(self):
- if self.delivery_amt < 1:
- if(self.carrier_id.id == 1 or self.shipping_cost_covered == 'indoteknik') and not self.env.context.get('active_id', []):
- if(self.carrier_id.id == 1):
- raise UserError('Untuk Kurir Indoteknik Delivery, Estimasi Ongkos Kirim Harus di isi')
+ is_indoteknik = self.carrier_id.id == 1 or self.shipping_cost_covered == 'indoteknik'
+ is_active_id = not self.env.context.get('active_id', [])
+
+ if is_indoteknik and is_active_id:
+ if self.delivery_amt == 0:
+ if self.carrier_id.id == 1:
+ raise UserError('Untuk Kurir Indoteknik Delivery, estimasi ongkos kirim belum diisi.')
+ else:
+ raise UserError('Untuk Shipping Covered Indoteknik, estimasi ongkos kirim belum diisi.')
+
+ if self.delivery_amt < 100:
+ if self.carrier_id.id == 1:
+ raise UserError('Untuk Kurir Indoteknik Delivery, estimasi ongkos kirim belum memenuhi tarif minimum.')
else:
- raise UserError('Untuk Shipping Covered Indoteknik, Estimasi Ongkos Kirim Harus di isi')
+ raise UserError('Untuk Shipping Covered Indoteknik, estimasi ongkos kirim belum memenuhi tarif minimum.')
+
+
+ # if self.delivery_amt < 5000:
+ # if (self.carrier_id.id == 1 or self.shipping_cost_covered == 'indoteknik') and not self.env.context.get('active_id', []):
+ # if self.carrier_id.id == 1:
+ # raise UserError('Untuk Kurir Indoteknik Delivery, estimasi ongkos kirim belum memenuhi jumlah minimum.')
+ # else:
+ # raise UserError('Untuk Shipping Covered Indoteknik, estimasi ongkos kirim belum memenuhi jumlah minimum.')
+
def override_allow_create_invoice(self):
if not self.env.user.is_accounting:
@@ -1029,7 +1081,16 @@ class SaleOrder(models.Model):
raise UserError("Product BOM belum dikonfirmasi di Manufacturing Orders. Silakan hubungi MD.")
else:
raise UserError("Product BOM tidak di temukan di manufacturing orders, silahkan hubungi MD")
+
+ def check_duplicate_product(self):
+ for order in self:
+ for line in order.order_line:
+ search_product = self.env['sale.order.line'].search([('product_id', '=', line.product_id.id), ('order_id', '=', order.id)])
+ if len(search_product) > 1:
+ raise UserError("Terdapat DUPLIKASI data pada Product {}".format(line.product_id.display_name))
+
def sale_order_approve(self):
+ self.check_duplicate_product()
self.check_product_bom()
self.check_credit_limit()
self.check_limit_so_to_invoice()
@@ -1270,6 +1331,7 @@ class SaleOrder(models.Model):
def action_confirm(self):
for order in self:
+ order.check_duplicate_product()
order.check_product_bom()
order.check_credit_limit()
order.check_limit_so_to_invoice()
@@ -1442,6 +1504,9 @@ class SaleOrder(models.Model):
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)
+ if order.ongkir_ke_xpdc:
+ total_margin -= order.ongkir_ke_xpdc
+
order.total_margin = total_margin
def _compute_total_percent_margin(self):
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index aa616e62..36129f00 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -26,11 +26,11 @@ _biteship_api_key = "biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1l
class StockPicking(models.Model):
_inherit = 'stock.picking'
_order = 'final_seq ASC'
- konfirm_koli_lines = fields.One2many('konfirm.koli', 'picking_id', string='Konfirm Koli', auto_join=True)
- scan_koli_lines = fields.One2many('scan.koli', 'picking_id', string='Scan Koli', auto_join=True)
- check_koli_lines = fields.One2many('check.koli', 'picking_id', string='Check Koli', auto_join=True)
+ konfirm_koli_lines = fields.One2many('konfirm.koli', 'picking_id', string='Konfirm Koli', auto_join=True, copy=False)
+ scan_koli_lines = fields.One2many('scan.koli', 'picking_id', string='Scan Koli', auto_join=True, copy=False)
+ check_koli_lines = fields.One2many('check.koli', 'picking_id', string='Check Koli', auto_join=True, copy=False)
- check_product_lines = fields.One2many('check.product', 'picking_id', string='Check Product', auto_join=True)
+ check_product_lines = fields.One2many('check.product', 'picking_id', string='Check Product', auto_join=True, copy=False)
barcode_product_lines = fields.One2many('barcode.product', 'picking_id', string='Barcode Product', auto_join=True)
is_internal_use = fields.Boolean('Internal Use', help='flag which is internal use or not')
account_id = fields.Many2one('account.account', string='Account')
@@ -100,12 +100,11 @@ class StockPicking(models.Model):
('pengajuan1', 'Approval Finance'),
('approved', 'Approved'),
], string='Approval Return Status', readonly=True, copy=False, index=True, tracking=3, help="Approval Status untuk Return")
- date_doc_kirim = fields.Datetime(string='Tanggal Kirim di SJ', help="Tanggal Kirim di cetakan SJ, tidak berpengaruh ke Accounting", tracking=True)
+ date_doc_kirim = fields.Datetime(string='Tanggal Kirim di SJ', help="Tanggal Kirim di cetakan SJ, tidak berpengaruh ke Accounting", tracking=True, copy=False)
note_logistic = fields.Selection([
- ('hold', 'Hold by Sales'),
+ ('wait_so_together', 'Tunggu SO Barengan'),
('not_paid', 'Customer belum bayar'),
- ('partial', 'Kirim Parsial'),
- ('indent', 'Indent'),
+ ('reserve_stock', 'Reserve Stock'),
('waiting_schedule', 'Menunggu Jadwal Kirim'),
('self_pickup', 'Barang belum di pickup Customer'),
('expedition_closed', 'Eskpedisi belum buka')
@@ -141,7 +140,8 @@ class StockPicking(models.Model):
('done', 'Done'),
('cancel', 'Cancelled'),
], string='Status Reserve', tracking=True, copy=False, help="The current state of the stock picking.")
- notee = fields.Text(string="Note")
+ notee = fields.Text(string="Note SJ", help="Catatan untuk kirim barang")
+ note_info = fields.Text(string="Note Logistix (Text)", help="Catatan untuk pengiriman")
state_approve_md = fields.Selection([
('waiting', 'Waiting For Approve by MD'),
('pending', 'Pending (perlu koordinasi dengan MD)'),
@@ -154,8 +154,33 @@ class StockPicking(models.Model):
# record.show_state_approve_md = record.location_id.id == 47 or record.location_id.complete_name == "Virtual Locations/Gudang Selisih"
quantity_koli = fields.Float(string="Quantity Koli", copy=False)
total_mapping_koli = fields.Float(string="Total Mapping Koli", compute='_compute_total_mapping_koli')
- so_lama = fields.Boolean('SO LAMA')
-
+ so_lama = fields.Boolean('SO LAMA', copy=False)
+ linked_manual_bu_out = fields.Many2one('stock.picking', string='BU Out', copy=False)
+
+ # def write(self, vals):
+ # if 'linked_manual_bu_out' in vals:
+ # for record in self:
+ # if (record.picking_type_code == 'internal'
+ # and 'BU/PICK/' in record.name):
+ # # Jika menghapus referensi (nilai di-set False/None)
+ # if record.linked_manual_bu_out and not vals['linked_manual_bu_out']:
+ # record.linked_manual_bu_out.state_packing = 'not_packing'
+ # # Jika menambahkan referensi baru
+ # elif vals['linked_manual_bu_out']:
+ # new_picking = self.env['stock.picking'].browse(vals['linked_manual_bu_out'])
+ # new_picking.state_packing = 'packing_done'
+ # return super().write(vals)
+
+ # @api.model
+ # def create(self, vals):
+ # record = super().create(vals)
+ # if (record.picking_type_code == 'internal'
+ # and 'BU/PICK/' in record.name
+ # and vals.get('linked_manual_bu_out')):
+ # picking = self.env['stock.picking'].browse(vals['linked_manual_bu_out'])
+ # picking.state_packing = 'packing_done'
+ # return record
+
@api.depends('konfirm_koli_lines', 'konfirm_koli_lines.pick_id', 'konfirm_koli_lines.pick_id.quantity_koli')
def _compute_total_mapping_koli(self):
for record in self:
@@ -220,21 +245,68 @@ class StockPicking(models.Model):
final_seq = fields.Float(string='Remaining Time')
shipping_method_so_id = fields.Many2one('delivery.carrier', string='Shipping Method SO', related='sale_id.carrier_id')
state_packing = fields.Selection([('not_packing', 'Belum Packing'), ('packing_done', 'Sudah Packing')], string='Packing Status')
-
- @api.constrains('konfirm_koli_lines')
- def _constrains_konfirm_koli_lines(self):
- now = datetime.datetime.utcnow()
- for picking in self:
- if len(picking.konfirm_koli_lines) > 0:
- picking.state_packing = 'packing_done'
- else:
- picking.state_packing = 'not_packing'
+ approval_invoice_date_id = fields.Many2one('approval.invoice.date', string='Approval Invoice Date')
+ last_update_date_doc_kirim = fields.Datetime(string='Last Update Tanggal Kirim')
+
+ def _check_date_doc_kirim_modification(self):
+ for record in self:
+ if record.last_update_date_doc_kirim and not self.env.context.get('from_button_approve'):
+ kirim_date = fields.Datetime.from_string(record.last_update_date_doc_kirim)
+ now = fields.Datetime.now()
+
+ deadline = kirim_date + timedelta(days=1)
+ deadline = deadline.replace(hour=10, minute=0, second=0)
+
+ if now > deadline:
+ raise ValidationError(
+ _("Anda tidak dapat mengubah Tanggal Kirim setelah jam 10:00 pada hari berikutnya!")
+ )
+
+ @api.constrains('date_doc_kirim')
+ def _constrains_date_doc_kirim(self):
+ for rec in self:
+ rec.calculate_line_no()
+
+ if rec.picking_type_code == 'outgoing' and 'BU/OUT/' in rec.name and rec.partner_id.id != 96868:
+ invoice = self.env['account.move'].search([('sale_id', '=', rec.sale_id.id), ('move_type', '=', 'out_invoice'), ('state', '=', 'posted')], limit=1, order='create_date desc')
+
+ if invoice and not self.env.context.get('active_model') == 'stock.picking':
+ rec._check_date_doc_kirim_modification()
+ if rec.date_doc_kirim != invoice.invoice_date and not self.env.context.get('from_button_approve'):
+ get_approval_invoice_date = self.env['approval.invoice.date'].search([('picking_id', '=', rec.id),('state', '=', 'draft')], limit=1)
+
+ if get_approval_invoice_date and get_approval_invoice_date.state == 'draft':
+ get_approval_invoice_date.date_doc_do = rec.date_doc_kirim
+ else:
+ approval_invoice_date = self.env['approval.invoice.date'].create({
+ 'picking_id': rec.id,
+ 'date_invoice': invoice.invoice_date,
+ 'date_doc_do': rec.date_doc_kirim,
+ 'sale_id': rec.sale_id.id,
+ 'move_id': invoice.id,
+ 'partner_id': rec.partner_id.id
+ })
+
+ rec.approval_invoice_date_id = approval_invoice_date.id
+
+ if approval_invoice_date:
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': { 'title': 'Notification', 'message': 'Invoice Date Tidak Sesuai, Document Approval Invoice Date Terbuat', 'next': {'type': 'ir.actions.act_window_close'} },
+ }
+
+ rec.last_update_date_doc_kirim = datetime.datetime.utcnow()
+
@api.constrains('scan_koli_lines')
def _constrains_scan_koli_lines(self):
now = datetime.datetime.utcnow()
for picking in self:
if len(picking.scan_koli_lines) > 0:
+ if len(picking.scan_koli_lines) != picking.total_mapping_koli:
+ raise UserError("Scan Koli Tidak Sesuai Dengan Total Mapping Koli")
+
picking.driver_departure_date = now
@api.depends('total_so_koli')
@@ -930,6 +1002,8 @@ class StockPicking(models.Model):
raise UserError('Hanya MD yang bisa Approve')
def button_validate(self):
+ self.check_invoice_date()
+ threshold_datetime = waktu(2025, 4, 11, 6, 26)
group_id = self.env.ref('indoteknik_custom.group_role_merchandiser').id
users_in_group = self.env['res.users'].search([('groups_id', 'in', [group_id])])
active_model = self.env.context.get('active_model')
@@ -941,7 +1015,6 @@ class StockPicking(models.Model):
if self.location_id.id == 47 and self.env.user.id in users_in_group.mapped('id'):
self.state_approve_md = 'done'
- threshold_datetime = waktu(2025, 4, 11, 6, 26)
if (len(self.konfirm_koli_lines) == 0
and 'BU/OUT/' in self.name
@@ -963,6 +1036,9 @@ class StockPicking(models.Model):
if len(self.check_koli_lines) == 0 and 'BU/PICK/' in self.name:
raise UserError(_("Tidak ada koli! Harap periksa kembali."))
+ if not self.linked_manual_bu_out and 'BU/PICK/' in self.name:
+ raise UserError(_("Isi BU Out terlebih dahulu!"))
+
if len(self.check_product_lines) == 0 and 'BU/PICK/' in self.name:
raise UserError(_("Tidak ada Check Product! Harap periksa kembali."))
@@ -1021,9 +1097,7 @@ class StockPicking(models.Model):
if self.picking_type_code == 'outgoing' and 'BU/OUT/' in self.name:
self.check_koli()
res = super(StockPicking, self).button_validate()
- self.calculate_line_no()
self.date_done = datetime.datetime.utcnow()
- self.driver_departure_date = datetime.datetime.utcnow()
self.state_reserve = 'done'
self.final_seq = 0
self.set_picking_code_out()
@@ -1056,6 +1130,28 @@ class StockPicking(models.Model):
self.send_mail_bills()
return res
+ def check_invoice_date(self):
+ for picking in self:
+ if picking.picking_type_code != 'outgoing' or 'BU/OUT/' not in picking.name or picking.partner_id.id == 96868:
+ continue
+
+ invoice = self.env['account.move'].search([('sale_id', '=', picking.sale_id.id)], limit=1)
+
+ if not invoice:
+ continue
+
+ if not picking.date_doc_kirim or not invoice.invoice_date:
+ raise UserError("Tanggal Kirim atau Tanggal Invoice belum diisi!")
+
+ picking_date = fields.Date.to_date(picking.date_doc_kirim)
+ invoice_date = fields.Date.to_date(invoice.invoice_date)
+
+ if picking_date != invoice_date:
+ raise UserError("Tanggal Kirim (%s) tidak sesuai dengan Tanggal Invoice (%s)!" % (
+ picking_date.strftime('%d-%m-%Y'),
+ invoice_date.strftime('%d-%m-%Y')
+ ))
+
def set_picking_code_out(self):
for picking in self:
# Check if picking meets criteria
@@ -1214,6 +1310,17 @@ class StockPicking(models.Model):
line.sale_line_id = sale_line.id
def write(self, vals):
+ if 'linked_manual_bu_out' in vals:
+ for record in self:
+ if (record.picking_type_code == 'internal'
+ and 'BU/PICK/' in record.name):
+ # Jika menghapus referensi (nilai di-set False/None)
+ if record.linked_manual_bu_out and not vals['linked_manual_bu_out']:
+ record.linked_manual_bu_out.state_packing = 'not_packing'
+ # Jika menambahkan referensi baru
+ elif vals['linked_manual_bu_out']:
+ new_picking = self.env['stock.picking'].browse(vals['linked_manual_bu_out'])
+ new_picking.state_packing = 'packing_done'
self._use_faktur(vals)
self.sync_sale_line(vals)
for picking in self:
@@ -1484,9 +1591,73 @@ class CheckProduct(models.Model):
index=True,
copy=False,
)
- product_id = fields.Many2one('product.product', string='Product', required=True)
- quantity = fields.Float(string='Quantity', default=1.0, required=True)
+ product_id = fields.Many2one('product.product', string='Product')
+ quantity = fields.Float(string='Quantity')
status = fields.Char(string='Status', compute='_compute_status')
+ code_product = fields.Char(string='Code Product')
+
+ @api.onchange('code_product')
+ def _onchange_code_product(self):
+ if not self.code_product:
+ return
+
+ # Cari product berdasarkan default_code, barcode, atau barcode_box
+ product = self.env['product.product'].search([
+ '|',
+ ('default_code', '=', self.code_product),
+ '|',
+ ('barcode', '=', self.code_product),
+ ('barcode_box', '=', self.code_product)
+ ], limit=1)
+
+ if not product:
+ raise UserError("Product tidak ditemukan")
+
+ # Jika scan barcode_box, set quantity sesuai qty_pcs_box
+ if product.barcode_box == self.code_product:
+ self.product_id = product.id
+ self.quantity = product.qty_pcs_box
+ self.code_product = product.default_code or product.barcode
+ # return {
+ # 'warning': {
+ # 'title': 'Info',8994175025871
+
+ # 'message': f'Product box terdeteksi. Quantity di-set ke {product.qty_pcs_box}'
+ # }
+ # }
+ else:
+ # Jika scan biasa
+ self.product_id = product.id
+ self.code_product = product.default_code or product.barcode
+ self.quantity = 1
+
+ def unlink(self):
+ # Get all affected pickings before deletion
+ pickings = self.mapped('picking_id')
+
+ # Store product_ids that will be deleted
+ deleted_product_ids = self.mapped('product_id')
+
+ # Perform the deletion
+ result = super(CheckProduct, self).unlink()
+
+ # After deletion, update moves for affected pickings
+ for picking in pickings:
+ # For products that were completely removed (no remaining check.product lines)
+ remaining_product_ids = picking.check_product_lines.mapped('product_id')
+ removed_product_ids = deleted_product_ids - remaining_product_ids
+
+ # Set quantity_done to 0 for moves of completely removed products
+ moves_to_reset = picking.move_ids_without_package.filtered(
+ lambda move: move.product_id in removed_product_ids
+ )
+ for move in moves_to_reset:
+ move.quantity_done = 0.0
+
+ # Also sync remaining products in case their totals changed
+ self._sync_check_product_to_moves(picking)
+
+ return result
@api.depends('quantity')
def _compute_status(self):
@@ -1586,7 +1757,7 @@ class CheckProduct(models.Model):
# Find existing lines for the same product, excluding the current line
existing_lines = record.picking_id.check_product_lines.filtered(
- lambda line: line.product_id == record.product_id and line.id != record.id
+ lambda line: line.product_id == record.product_id
)
if existing_lines:
@@ -1594,7 +1765,7 @@ class CheckProduct(models.Model):
first_line = existing_lines[0]
# Calculate the total quantity after addition
- total_quantity = sum(existing_lines.mapped('quantity')) - record.quantity
+ total_quantity = sum(existing_lines.mapped('quantity'))
if total_quantity > total_qty_in_moves:
raise UserError((
@@ -1602,7 +1773,7 @@ class CheckProduct(models.Model):
) % (record.product_id.display_name))
else:
# Check if the quantity exceeds the allowed total
- if record.quantity > total_qty_in_moves:
+ if record.quantity == total_qty_in_moves:
raise UserError((
"Quantity Product '%s' sudah melebihi quantity demand."
) % (record.product_id.display_name))
@@ -1626,9 +1797,21 @@ class BarcodeProduct(models.Model):
product_id = fields.Many2one('product.product', string='Product', required=True)
barcode = fields.Char(string='Barcode')
+ def check_duplicate_barcode(self):
+ barcode_product = self.env['product.product'].search([('barcode', '=', self.barcode)])
+
+ if barcode_product:
+ raise UserError('Barcode sudah digunakan {}'.format(barcode_product.display_name))
+
+ barcode_box = self.env['product.product'].search([('barcode_box', '=', self.barcode)])
+
+ if barcode_box:
+ raise UserError('Barcode box sudah digunakan {}'.format(barcode_box.display_name))
+
@api.constrains('barcode')
def send_barcode_to_product(self):
for record in self:
+ record.check_duplicate_barcode()
if record.barcode and not record.product_id.barcode:
record.product_id.barcode = record.barcode
else:
@@ -1683,15 +1866,25 @@ class ScanKoli(models.Model):
string="Progress Scan Koli",
compute="_compute_scan_koli_progress"
)
+ code_koli = fields.Char(string='Code Koli')
- def _compute_scan_koli_progress(self):
- for scan in self:
- if scan.picking_id:
- all_scans = self.env['scan.koli'].search([('picking_id', '=', scan.picking_id.id)], order='id')
- if all_scans:
- scan_index = list(all_scans).index(scan) + 1 # Nomor urut scan
- total_so_koli = scan.picking_id.total_so_koli
- scan.scan_koli_progress = f"{scan_index}/{total_so_koli}" if total_so_koli else "0/0"
+ @api.onchange('code_koli')
+ def _onchange_code_koli(self):
+ if self.code_koli:
+ koli = self.env['sales.order.koli'].search([('koli_id.koli', '=', self.code_koli)], limit=1)
+ if koli:
+ self.write({'koli_id': koli.id})
+ else:
+ raise UserError('Koli tidak ditemukan')
+
+ # def _compute_scan_koli_progress(self):
+ # for scan in self:
+ # if scan.picking_id:
+ # all_scans = self.env['scan.koli'].search([('picking_id', '=', scan.picking_id.id)], order='id')
+ # if all_scans:
+ # scan_index = list(all_scans).index(scan) + 1 # Nomor urut scan
+ # total_so_koli = scan.picking_id.total_so_koli
+ # scan.scan_koli_progress = f"{scan_index}/{total_so_koli}" if total_so_koli else "0/0"
@api.onchange('koli_id')
def _onchange_koli_compare_with_konfirm_koli(self):
@@ -1763,13 +1956,21 @@ class ScanKoli(models.Model):
def _compute_scan_koli_progress(self):
for scan in self:
- if scan.picking_id:
+ if not scan.picking_id:
+ scan.scan_koli_progress = "0/0"
+ continue
+
+ try:
all_scans = self.env['scan.koli'].search([('picking_id', '=', scan.picking_id.id)], order='id')
if all_scans:
- scan_index = list(all_scans).index(scan) + 1 # Nomor urut scan
- total_so_koli = scan.picking_id.total_so_koli
- scan.scan_koli_progress = f"{scan_index}/{total_so_koli}" if total_so_koli else "0/0"
-
+ scan_index = list(all_scans).index(scan) + 1
+ total_so_koli = scan.picking_id.total_so_koli or 0
+ scan.scan_koli_progress = f"{scan_index}/{total_so_koli}"
+ else:
+ scan.scan_koli_progress = "0/0"
+ except Exception:
+ # Fallback in case of any error
+ scan.scan_koli_progress = "0/0"
@api.constrains('picking_id', 'picking_id.total_so_koli')
def _check_koli_validation(self):
for scan in self.picking_id.scan_koli_lines:
diff --git a/indoteknik_custom/models/voucher.py b/indoteknik_custom/models/voucher.py
index 101d4bcf..7b458d01 100644
--- a/indoteknik_custom/models/voucher.py
+++ b/indoteknik_custom/models/voucher.py
@@ -265,3 +265,19 @@ class Voucher(models.Model):
tnc.append(f'<li>{line_tnc}</li>')
return ' '.join(tnc)
+ # copy semua data kalau diduplicate
+ def copy(self, default=None):
+ default = dict(default or {})
+ voucher_lines = []
+
+ for line in self.voucher_line:
+ voucher_lines.append((0, 0, {
+ 'manufacture_id': line.manufacture_id.id,
+ 'discount_amount': line.discount_amount,
+ 'discount_type': line.discount_type,
+ 'min_purchase_amount': line.min_purchase_amount,
+ 'max_discount_amount': line.max_discount_amount,
+ }))
+
+ default['voucher_line'] = voucher_lines
+ return super(Voucher, self).copy(default) \ No newline at end of file
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index 4d164bcb..46ab4c1f 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -138,6 +138,7 @@ access_shipment_group,access.shipment.group,model_shipment_group,,1,1,1,1
access_shipment_group_line,access.shipment.group.line,model_shipment_group_line,,1,1,1,1
access_sales_order_reject,access.sales.order.reject,model_sales_order_reject,,1,1,1,1
access_approval_date_doc,access.approval.date.doc,model_approval_date_doc,,1,1,1,1
+access_approval_invoice_date,access.approval.invoice.date,model_approval_invoice_date,,1,1,1,1
access_account_tax,access.account.tax,model_account_tax,,1,1,1,1
access_approval_unreserve,access.approval.unreserve,model_approval_unreserve,,1,1,1,1
access_approval_unreserve_line,access.approval.unreserve.line,model_approval_unreserve_line,,1,1,1,1
diff --git a/indoteknik_custom/views/approval_invoice_date.xml b/indoteknik_custom/views/approval_invoice_date.xml
new file mode 100644
index 00000000..31f346e7
--- /dev/null
+++ b/indoteknik_custom/views/approval_invoice_date.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<odoo>
+ <record id="approval_invoice_date_tree" model="ir.ui.view">
+ <field name="name">approval.invoice.date.tree</field>
+ <field name="model">approval.invoice.date</field>
+ <field name="arch" type="xml">
+ <tree>
+ <field name="number"/>
+ <field name="picking_id"/>
+ <field name="partner_id"/>
+ <field name="sale_id"/>
+ <field name="date_doc_do"/>
+ <field name="date_invoice"/>
+ <field name="state" widget="badge" decoration-danger="state == 'cancel'"
+ decoration-success="state == 'done'"
+ decoration-info="state == 'draft'"/>
+ <field name="approve_date"/>
+ <field name="approve_by"/>
+ <field name="create_uid"/>
+ </tree>
+ </field>
+ </record>
+
+ <record id="approval_invoice_date_form" model="ir.ui.view">
+ <field name="name">approval.invoice.date.form</field>
+ <field name="model">approval.invoice.date</field>
+ <field name="arch" type="xml">
+ <form>
+ <header>
+ <button name="button_approve"
+ string="Approve"
+ type="object"
+ attrs="{'invisible': [('state', '=', 'done')]}"
+ />
+ <button name="button_cancel"
+ string="Cancel"
+ type="object"
+ attrs="{'invisible': [('state', '=', 'cancel')]}"
+ />
+ <field name="state" widget="statusbar"
+ statusbar_visible="draft,cancel,done"
+ statusbar_colors='{"cancel":"red", "done":"green"}'/>
+ </header>
+ <sheet string="Approval Invoice Date">
+ <group>
+ <group>
+ <field name="number"/>
+ <field name="picking_id"/>
+ <field name="partner_id"/>
+ <field name="sale_id"/>
+ <field name="move_id"/>
+ <field name="date_doc_do"/>
+ <field name="date_invoice"/>
+ <field name="approve_date"/>
+ <field name="approve_by"/>
+ <field name="create_uid"/>
+ <field name="note" attrs="{'invisible': [('state', '!=', 'cancel')]}"/>
+ </group>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="view_approval_invoice_date_filter" model="ir.ui.view">
+ <field name="name">approval.invoice.date.list.select</field>
+ <field name="model">approval.invoice.date</field>
+ <field name="priority" eval="15"/>
+ <field name="arch" type="xml">
+ <search string="Search Approval Invoice Date">
+ <field name="number"/>
+ <field name="partner_id"/>
+ <field name="picking_id"/>
+ <field name="sale_id"/>
+ </search>
+ </field>
+ </record>
+
+ <record id="approval_invoice_date_action" model="ir.actions.act_window">
+ <field name="name">Approval Invoice Date</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">approval.invoice.date</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
+ <menuitem id="menu_approval_invoice_date" name="Approval Invoice Date"
+ parent="account.menu_finance_receivables"
+ action="approval_invoice_date_action"
+ sequence="100"
+ />
+
+</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/barcoding_product.xml b/indoteknik_custom/views/barcoding_product.xml
index c7473d39..92064ee5 100644
--- a/indoteknik_custom/views/barcoding_product.xml
+++ b/indoteknik_custom/views/barcoding_product.xml
@@ -34,12 +34,13 @@
<group>
<field name="product_id" required="1"/>
<field name="type" required="1"/>
- <field name="quantity" attrs="{'invisible': [['type', 'in', ('barcoding')]], 'required': [['type', 'not in', ('barcoding')]]}"/>
+ <field name="quantity" attrs="{'invisible': [['type', 'in', ('barcoding','barcoding_box')]], 'required': [['type', 'not in', ('barcoding')]]}"/>
<field name="barcode" attrs="{'invisible': [['type', 'in', ('print')]], 'required': [['type', 'not in', ('print')]]}"/>
+ <field name="qty_pcs_box" attrs="{'invisible': [['type', 'in', ('print','barcoding')]], 'required': [['type', 'not in', ('print')]]}"/>
</group>
</group>
<notebook>
- <page string="Line" attrs="{'invisible': [['type', 'in', ('barcoding')]]}">
+ <page string="Line" attrs="{'invisible': [['type', 'in', ('barcoding','barcoding_box')]]}">
<field name="barcoding_product_line"/>
</page>
</notebook>
diff --git a/indoteknik_custom/views/ir_sequence.xml b/indoteknik_custom/views/ir_sequence.xml
index dfb56100..9f980751 100644
--- a/indoteknik_custom/views/ir_sequence.xml
+++ b/indoteknik_custom/views/ir_sequence.xml
@@ -21,6 +21,16 @@
<field name="number_increment">1</field>
</record>
+ <record id="sequence_invoice_date" model="ir.sequence">
+ <field name="name">Approval Invoice Date</field>
+ <field name="code">approval.invoice.date</field>
+ <field name="active">TRUE</field>
+ <field name="prefix">AID/%(year)s/</field>
+ <field name="padding">5</field>
+ <field name="number_next">1</field>
+ <field name="number_increment">1</field>
+ </record>
+
<record id="sequence_vendor_approval" model="ir.sequence">
<field name="name">Vendor Approval</field>
<field name="code">vendor.approval</field>
diff --git a/indoteknik_custom/views/product_template.xml b/indoteknik_custom/views/product_template.xml
index af21984a..076a8082 100755
--- a/indoteknik_custom/views/product_template.xml
+++ b/indoteknik_custom/views/product_template.xml
@@ -62,6 +62,8 @@
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="arch" type="xml">
<field name="last_update_solr" position="after">
+ <field name="barcode_box" />
+ <field name="qty_pcs_box" />
<field name="clean_website_description" />
<field name="qr_code_variant" widget="image" readonly="True"/>
</field>
diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml
index 2c64181e..79a095fb 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -1,180 +1,214 @@
-<?xml version="1.0" encoding="UTF-8" ?>
+<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<record id="sale_order_form_view_inherit" model="ir.ui.view">
<field name="name">Sale Order</field>
<field name="model">sale.order</field>
- <field name="inherit_id" ref="sale.view_order_form"/>
+ <field name="inherit_id" ref="sale.view_order_form" />
<field name="arch" type="xml">
<button id="action_confirm" position="after">
<button name="calculate_line_no"
- string="Create No"
- type="object"
+ string="Create No"
+ type="object"
/>
<button name="sale_order_approve"
- string="Ask Approval"
- type="object"
- attrs="{'invisible': [('approval_status', '=', ['approved'])]}"
+ string="Ask Approval"
+ type="object"
+ attrs="{'invisible': [('approval_status', '=', ['approved'])]}"
/>
<button name="action_web_approve"
- string="Web Approve"
- type="object"
- attrs="{'invisible': ['|', '|', ('create_uid', '!=', 25), ('web_approval', '!=', False), ('state', '!=', 'draft')]}"
+ string="Web Approve"
+ type="object"
+ attrs="{'invisible': ['|', '|', ('create_uid', '!=', 25), ('web_approval', '!=', False), ('state', '!=', 'draft')]}"
/>
- <button name="indoteknik_custom.action_view_uangmuka_penjualan" string="UangMuka"
- type="action" attrs="{'invisible': [('approval_status', '!=', 'approved')]}"/>
+ <button name="indoteknik_custom.action_view_uangmuka_penjualan"
+ string="UangMuka"
+ type="action" attrs="{'invisible': [('approval_status', '!=', 'approved')]}" />
</button>
<field name="payment_term_id" position="after">
- <field name="create_uid" invisible="1"/>
- <field name="create_date" invisible="1"/>
- <field name="shipping_cost_covered" attrs="{'required': ['|', ('create_date', '&gt;', '2023-06-15'), ('create_date', '=', False)]}"/>
- <field name="shipping_paid_by" attrs="{'required': ['|', ('create_date', '&gt;', '2023-06-15'), ('create_date', '=', False)]}"/>
- <field name="delivery_amt"/>
- <field name="fee_third_party"/>
- <field name="biaya_lain_lain"/>
- <field name="total_percent_margin"/>
- <field name="total_margin_excl_third_party" readonly="1"/>
- <field name="type_promotion"/>
- <label for="voucher_id"/>
+ <field name="create_uid" invisible="1" />
+ <field name="create_date" invisible="1" />
+ <field name="shipping_cost_covered"
+ attrs="{'required': ['|', ('create_date', '&gt;', '2023-06-15'), ('create_date', '=', False)]}" />
+ <field name="shipping_paid_by"
+ attrs="{'required': ['|', ('create_date', '&gt;', '2023-06-15'), ('create_date', '=', False)]}" />
+ <field name="delivery_amt" />
+ <field name="ongkir_ke_xpdc" />
+ <field name="metode_kirim_ke_xpdc" />
+ <field name="fee_third_party" />
+ <field name="biaya_lain_lain" />
+ <field name="total_percent_margin" />
+ <field name="total_margin_excl_third_party" readonly="1" />
+ <field name="type_promotion" />
+ <label for="voucher_id" />
<div class="o_row">
- <field name="voucher_id" id="voucher_id" attrs="{'readonly': ['|', ('state', 'not in', ['draft', 'sent']), ('applied_voucher_id', '!=', False)]}"/>
+ <field name="voucher_id" id="voucher_id"
+ attrs="{'readonly': ['|', ('state', 'not in', ['draft', 'sent']), ('applied_voucher_id', '!=', False)]}" />
<field name="applied_voucher_id" invisible="1" />
- <button name="action_apply_voucher" type="object" string="Apply" confirm="Anda yakin untuk menggunakan voucher?" help="Apply the selected voucher" class="btn-link mb-1 px-0" icon="fa-plus"
+ <button name="action_apply_voucher" type="object" string="Apply"
+ confirm="Anda yakin untuk menggunakan voucher?"
+ help="Apply the selected voucher" class="btn-link mb-1 px-0"
+ icon="fa-plus"
attrs="{'invisible': ['|', '|', ('voucher_id', '=', False), ('state', 'not in', ['draft', 'sent']), ('applied_voucher_id', '!=', False)]}"
/>
- <button name="cancel_voucher" type="object" string="Cancel" confirm="Anda yakin untuk membatalkan penggunaan voucher?" help="Cancel applied voucher" class="btn-link mb-1 px-0" icon="fa-times"
+ <button name="cancel_voucher" type="object" string="Cancel"
+ confirm="Anda yakin untuk membatalkan penggunaan voucher?"
+ help="Cancel applied voucher" class="btn-link mb-1 px-0" icon="fa-times"
attrs="{'invisible': ['|', ('applied_voucher_id', '=', False), ('state', 'not in', ['draft','sent'])]}"
/>
</div>
- <label for="voucher_shipping_id"/>
+ <label for="voucher_shipping_id" />
<div class="o_row">
- <field name="voucher_shipping_id" id="voucher_shipping_id" attrs="{'readonly': ['|', ('state', 'not in', ['draft', 'sent']), ('applied_voucher_shipping_id', '!=', False)]}"/>
+ <field name="voucher_shipping_id" id="voucher_shipping_id"
+ attrs="{'readonly': ['|', ('state', 'not in', ['draft', 'sent']), ('applied_voucher_shipping_id', '!=', False)]}" />
<field name="applied_voucher_shipping_id" invisible="1" />
- <button name="action_apply_voucher_shipping" type="object" string="Apply" confirm="Anda yakin untuk menggunakan voucher?" help="Apply the selected voucher" class="btn-link mb-1 px-0" icon="fa-plus"
+ <button name="action_apply_voucher_shipping" type="object" string="Apply"
+ confirm="Anda yakin untuk menggunakan voucher?"
+ help="Apply the selected voucher" class="btn-link mb-1 px-0"
+ icon="fa-plus"
attrs="{'invisible': ['|', '|', ('voucher_id', '=', False), ('state', 'not in', ['draft', 'sent']), ('applied_voucher_shipping_id', '!=', False)]}"
/>
- <button name="cancel_voucher_shipping" type="object" string="Cancel" confirm="Anda yakin untuk membatalkan penggunaan voucher?" help="Cancel applied voucher" class="btn-link mb-1 px-0" icon="fa-times"
+ <button name="cancel_voucher_shipping" type="object" string="Cancel"
+ confirm="Anda yakin untuk membatalkan penggunaan voucher?"
+ help="Cancel applied voucher" class="btn-link mb-1 px-0" icon="fa-times"
attrs="{'invisible': ['|', ('applied_voucher_shipping_id', '=', False), ('state', 'not in', ['draft','sent'])]}"
/>
</div>
<button name="calculate_selling_price"
- string="Calculate Selling Price"
- type="object"
+ string="Calculate Selling Price"
+ type="object"
/>
</field>
<field name="source_id" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="user_id" position="after">
- <field name="helper_by_id" readonly="1"/>
- <field name="compute_fullfillment" invisible="1"/>
+ <field name="helper_by_id" readonly="1" />
+ <field name="compute_fullfillment" invisible="1" />
</field>
<field name="tag_ids" position="after">
- <field name="eta_date_start"/>
- <t t-esc="' to '"/>
- <field name="eta_date" readonly="1"/>
+ <field name="eta_date_start" />
+ <t t-esc="' to '" />
+ <field name="eta_date" readonly="1" />
<field name="expected_ready_to_ship" />
- <field name="flash_sale"/>
- <field name="margin_after_delivery_purchase"/>
- <field name="percent_margin_after_delivery_purchase"/>
- <field name="total_weight"/>
- <field name="pareto_status"/>
+ <field name="flash_sale" />
+ <field name="margin_after_delivery_purchase" />
+ <field name="percent_margin_after_delivery_purchase" />
+ <field name="total_weight" />
+ <field name="pareto_status" />
</field>
<field name="analytic_account_id" position="after">
- <field name="customer_type" required="1"/>
- <field name="npwp" placeholder='99.999.999.9-999.999' required="1"/>
- <field name="sppkp" attrs="{'required': [('customer_type', '=', 'pkp')]}"/>
- <field name="email" required="1"/>
- <field name="unreserve_id"/>
- <field name="due_id" readonly="1"/>
- <field name="vendor_approval_id" readonly="1" widget="many2many_tags"/>
- <field name="source_id" domain="[('id', 'in', [32, 59, 60, 61])]" required="1"/>
+ <field name="customer_type" required="1" />
+ <field name="npwp" placeholder='99.999.999.9-999.999' required="1" />
+ <field name="sppkp" attrs="{'required': [('customer_type', '=', 'pkp')]}" />
+ <field name="email" required="1" />
+ <field name="unreserve_id" />
+ <field name="due_id" readonly="1" />
+ <field name="vendor_approval_id" readonly="1" widget="many2many_tags" />
+ <field name="source_id" domain="[('id', 'in', [32, 59, 60, 61])]" required="1" />
<button name="override_allow_create_invoice"
- string="Override Create Invoice"
- type="object"
+ string="Override Create Invoice"
+ type="object"
/>
- <button string="Estimate Shipping" type="object" name="action_estimate_shipping"/>
+ <button string="Estimate Shipping" type="object" name="action_estimate_shipping" />
</field>
<field name="partner_shipping_id" position="after">
- <field name="real_shipping_id"/>
- <field name="real_invoice_id"/>
+ <field name="real_shipping_id" />
+ <field name="real_invoice_id" />
<field name="approval_status" />
- <field name="sales_tax_id" domain="[('type_tax_use','=','sale'), ('active', '=', True)]" required="1"/>
- <field name="carrier_id" required="1"/>
- <field name="delivery_service_type" readonly="1"/>
- <field name="shipping_option_id"/>
+ <field name="sales_tax_id"
+ domain="[('type_tax_use','=','sale'), ('active', '=', True)]" required="1" />
+ <field name="carrier_id" required="1" />
+ <field name="delivery_service_type" readonly="1" />
+ <field name="shipping_option_id" />
</field>
<field name="medium_id" position="after">
- <field name="date_doc_kirim" readonly="1"/>
- <field name="notification" readonly="1"/>
+ <field name="date_doc_kirim" readonly="1" />
+ <field name="notification" readonly="1" />
</field>
- <xpath expr="//form/sheet/notebook/page/field[@name='order_line']" position="attributes">
+ <xpath expr="//form/sheet/notebook/page/field[@name='order_line']"
+ position="attributes">
<attribute name="attrs">
{'readonly': [('state', 'in', ('done','cancel'))]}
</attribute>
</xpath>
- <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree" position="inside">
- <field name="desc_updatable" invisible="1"/>
+ <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree"
+ position="inside">
+ <field name="desc_updatable" invisible="1" />
</xpath>
- <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='name']" position="attributes">
+ <xpath
+ expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='name']"
+ position="attributes">
<attribute name="modifiers">
{'readonly': [('desc_updatable', '=', False)]}
</attribute>
</xpath>
- <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='price_unit']" position="attributes">
+ <xpath
+ expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='price_unit']"
+ position="attributes">
<attribute name="attrs">
{
- 'readonly': [
- '|',
- ('qty_invoiced', '>', 0),
- ('parent.approval_status', '!=', False)
- ]
+ 'readonly': [
+ '|',
+ ('qty_invoiced', '>', 0),
+ ('parent.approval_status', '!=', False)
+ ]
}
</attribute>
</xpath>
<div name="invoice_lines" position="before">
- <div name="vendor_id" groups="base.group_no_one" attrs="{'invisible': [('display_type', '!=', False)]}">
- <label for="vendor_id"/>
+ <div name="vendor_id" groups="base.group_no_one"
+ attrs="{'invisible': [('display_type', '!=', False)]}">
+ <label for="vendor_id" />
<div name="vendor_id">
- <field name="vendor_id"
- attrs="{'readonly': [('parent.approval_status', '=', 'approved')]}"
- domain="[('parent_id', '=', False)]"
- options="{'no_create': True}" class="oe_inline" />
+ <field name="vendor_id"
+ attrs="{'readonly': [('parent.approval_status', '=', 'approved')]}"
+ domain="[('parent_id', '=', False)]"
+ options="{'no_create': True}" class="oe_inline" />
</div>
</div>
</div>
-
+
<div name="invoice_lines" position="before">
- <div name="purchase_price" groups="base.group_no_one" attrs="{'invisible': [('display_type', '!=', False)]}">
- <label for="purchase_price"/>
- <field name="purchase_price"/>
+ <div name="purchase_price" groups="base.group_no_one"
+ attrs="{'invisible': [('display_type', '!=', False)]}">
+ <label for="purchase_price" />
+ <field name="purchase_price" />
</div>
</div>
<div name="invoice_lines" position="before">
- <div name="purchase_tax_id" groups="base.group_no_one" attrs="{'invisible': [('display_type', '!=', False)]}">
- <label for="purchase_tax_id"/>
+ <div name="purchase_tax_id" groups="base.group_no_one"
+ attrs="{'invisible': [('display_type', '!=', False)]}">
+ <label for="purchase_tax_id" />
<div name="purchase_tax_id">
- <field name="purchase_tax_id"/>
+ <field name="purchase_tax_id" />
</div>
</div>
</div>
<div name="invoice_lines" position="before">
- <div name="item_percent_margin" groups="base.group_no_one" attrs="{'invisible': [('display_type', '!=', False)]}">
- <label for="item_percent_margin"/>
- <field name="item_percent_margin"/>
+ <div name="item_percent_margin" groups="base.group_no_one"
+ attrs="{'invisible': [('display_type', '!=', False)]}">
+ <label for="item_percent_margin" />
+ <field name="item_percent_margin" />
</div>
</div>
<div name="invoice_lines" position="before">
- <div name="price_subtotal" groups="base.group_no_one" attrs="{'invisible': [('display_type', '!=', False)]}">
- <label for="price_subtotal"/>
- <field name="price_subtotal"/>
+ <div name="price_subtotal" groups="base.group_no_one"
+ attrs="{'invisible': [('display_type', '!=', False)]}">
+ <label for="price_subtotal" />
+ <field name="price_subtotal" />
</div>
</div>
- <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='price_total']" position="after">
- <field name="qty_free_bu" optional="hide"/>
- <field name="vendor_id" attrs="{'readonly': [('parent.approval_status', '=', 'approved')], 'invisible': [('display_type', '!=', False)]}" domain="[('parent_id', '=', False)]" options="{'no_create':True}"/>
- <field name="vendor_md_id" optional="hide"/>
- <field name="purchase_price" attrs="
+ <xpath
+ expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='price_total']"
+ position="after">
+ <field name="qty_free_bu" optional="hide" />
+ <field name="vendor_id"
+ attrs="{'readonly': [('parent.approval_status', '=', 'approved')], 'invisible': [('display_type', '!=', False)]}"
+ domain="[('parent_id', '=', False)]" options="{'no_create':True}" />
+ <field name="vendor_md_id" optional="hide" />
+ <field name="purchase_price"
+ attrs="
{
'readonly': [
'|',
@@ -182,56 +216,72 @@
('parent.approval_status', '!=', False)
]
}
- "/>
- <field name="purchase_price_md" optional="hide"/>
- <field name="purchase_tax_id" attrs="{'readonly': [('parent.approval_status', '!=', False)]}" domain="[('type_tax_use','=','purchase')]" options="{'no_create':True}"/>
- <field name="item_percent_margin"/>
- <field name="item_margin" optional="hide"/>
- <field name="margin_md" optional="hide"/>
- <field name="note" optional="hide"/>
- <field name="note_procurement" optional="hide"/>
- <field name="vendor_subtotal" optional="hide"/>
- <field name="weight" optional="hide"/>
- <field name="amount_voucher_disc" string="Voucher" readonly="1" optional="hide"/>
- <field name="order_promotion_id" string="Promotion" readonly="1" optional="hide"/>
+ " />
+ <field name="purchase_price_md" optional="hide" />
+ <field name="purchase_tax_id"
+ attrs="{'readonly': [('parent.approval_status', '!=', False)]}"
+ domain="[('type_tax_use','=','purchase')]" options="{'no_create':True}" />
+ <field name="item_percent_margin" />
+ <field name="item_margin" optional="hide" />
+ <field name="margin_md" optional="hide" />
+ <field name="note" optional="hide" />
+ <field name="note_procurement" optional="hide" />
+ <field name="vendor_subtotal" optional="hide" />
+ <field name="weight" optional="hide" />
+ <field name="amount_voucher_disc" string="Voucher" readonly="1" optional="hide" />
+ <field name="order_promotion_id" string="Promotion" readonly="1" optional="hide" />
</xpath>
- <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='product_id']" position="before">
- <field name="line_no" readonly="1" optional="hide"/>
+ <xpath
+ expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='product_id']"
+ position="before">
+ <field name="line_no" readonly="1" optional="hide" />
</xpath>
- <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='qty_delivered']" position="before">
- <field name="qty_reserved" invisible="1"/>
- <field name="reserved_from" readonly="1" optional="hide"/>
+ <xpath
+ expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='qty_delivered']"
+ position="before">
+ <field name="qty_reserved" invisible="1" />
+ <field name="reserved_from" readonly="1" optional="hide" />
</xpath>
- <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='product_id']" position="attributes">
+ <xpath
+ expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='product_id']"
+ position="attributes">
<attribute name="options">{'no_create': True}</attribute>
</xpath>
- <!-- <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='tax_id']" position="attributes">
+ <!-- <xpath
+ expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='tax_id']"
+ position="attributes">
<attribute name="required">1</attribute>
</xpath> -->
<field name="amount_total" position="after">
- <field name="grand_total"/>
+ <field name="grand_total" />
<label for="amount_voucher_disc" string="Voucher" />
<div>
- <field class="mb-0" name="amount_voucher_disc" string="Voucher" readonly="1"/>
- <div class="text-right mb-2"><small>*Hanya informasi</small></div>
+ <field class="mb-0" name="amount_voucher_disc" string="Voucher" readonly="1" />
+ <div class="text-right mb-2">
+ <small>*Hanya informasi</small>
+ </div>
</div>
<label for="amount_voucher_shipping_disc" string="Voucher Shipping" />
<div>
- <field class="mb-0" name="amount_voucher_shipping_disc" string="Voucher Shipping" readonly="1"/>
- <div class="text-right mb-2"><small>*Hanya informasi</small></div>
+ <field class="mb-0" name="amount_voucher_shipping_disc"
+ string="Voucher Shipping" readonly="1" />
+ <div class="text-right mb-2">
+ <small>*Hanya informasi</small>
+ </div>
</div>
- <field name="total_margin"/>
- <field name="total_percent_margin"/>
+ <field name="total_margin" />
+ <field name="total_percent_margin" />
</field>
<field name="effective_date" position="after">
- <field name="carrier_id"/>
- <field name="estimated_arrival_days"/>
- <field name="picking_iu_id"/>
- <field name="note_ekspedisi"/>
+ <field name="carrier_id" />
+ <field name="estimated_arrival_days" />
+ <field name="picking_iu_id" />
+ <field name="note_ekspedisi" />
</field>
<field name="carrier_id" position="attributes">
<attribute name="attrs">
- {'readonly': [('approval_status', '=', 'approved'), ('state', 'not in', ['cancel','draft'])]}
+ {'readonly': [('approval_status', '=', 'approved'), ('state', 'not in',
+ ['cancel','draft'])]}
</attribute>
</field>
@@ -239,22 +289,22 @@
<page string="Website" name="customer_purchase_order">
<group>
<group>
- <field name="partner_purchase_order_name" readonly="True"/>
- <field name="partner_purchase_order_description" readonly="True"/>
- <field name="partner_purchase_order_file" readonly="True"/>
- <field name="note_website" readonly="True"/>
- <field name="web_approval" readonly="True"/>
+ <field name="partner_purchase_order_name" readonly="True" />
+ <field name="partner_purchase_order_description" readonly="True" />
+ <field name="partner_purchase_order_file" readonly="True" />
+ <field name="note_website" readonly="True" />
+ <field name="web_approval" readonly="True" />
</group>
<group>
<button name="generate_payment_link_midtrans_sales_order"
- string="Create Payment Link"
- type="object"
+ string="Create Payment Link"
+ type="object"
/>
- <field name="payment_link_midtrans" readonly="True" widget="url"/>
- <field name="gross_amount" readonly="True"/>
- <field name="payment_type" readonly="True"/>
- <field name="payment_status" readonly="True"/>
- <field name="payment_qr_code" widget="image" readonly="True"/>
+ <field name="payment_link_midtrans" readonly="True" widget="url" />
+ <field name="gross_amount" readonly="True" />
+ <field name="payment_type" readonly="True" />
+ <field name="payment_status" readonly="True" />
+ <field name="payment_qr_code" widget="image" readonly="True" />
</group>
</group>
</page>
@@ -275,89 +325,91 @@
</field>
</page>
<page string="Matches PO" name="page_matches_po" invisible="1">
- <field name="order_sales_match_line" readonly="1"/>
+ <field name="order_sales_match_line" readonly="1" />
</page>
<!-- <page string="Fullfillment" name="page_sale_order_fullfillment">
<field name="fullfillment_line" readonly="1"/>
</page> -->
<page string="Fulfillment v2" name="page_sale_order_fullfillment2">
- <field name="fulfillment_line_v2" readonly="1"/>
+ <field name="fulfillment_line_v2" readonly="1" />
</page>
<page string="Reject Line" name="page_sale_order_reject_line">
- <field name="reject_line" readonly="1"/>
+ <field name="reject_line" readonly="1" />
</page>
<page string="Koli" name="page_sales_order_koli_line">
- <field name="koli_lines" readonly="1"/>
+ <field name="koli_lines" readonly="1" />
</page>
</page>
</field>
</record>
- <!-- Wizard for Reject Reason -->
- <record id="view_cancel_reason_order_form" model="ir.ui.view">
- <field name="name">cancel.reason.order.form</field>
- <field name="model">cancel.reason.order</field>
- <field name="arch" type="xml">
- <form string="Cancel Reason">
- <group>
- <field name="reason_cancel" widget="selection"/>
- <field name="attachment_bukti" widget="many2many_binary" required="1"/>
- <field name="nomor_so_pengganti" attrs="{'invisible': [('reason_cancel', '!=', 'ganti_quotation')]}"/>
- </group>
- <footer>
- <button string="Confirm" type="object" name="confirm_reject" class="btn-primary"/>
- <button string="Cancel" class="btn-secondary" special="cancel"/>
- </footer>
- </form>
- </field>
- </record>
+ <!-- Wizard for Reject Reason -->
+ <record id="view_cancel_reason_order_form" model="ir.ui.view">
+ <field name="name">cancel.reason.order.form</field>
+ <field name="model">cancel.reason.order</field>
+ <field name="arch" type="xml">
+ <form string="Cancel Reason">
+ <group>
+ <field name="reason_cancel" widget="selection" />
+ <field name="attachment_bukti" widget="many2many_binary" required="1" />
+ <field name="nomor_so_pengganti"
+ attrs="{'invisible': [('reason_cancel', '!=', 'ganti_quotation')]}" />
+ </group>
+ <footer>
+ <button string="Confirm" type="object" name="confirm_reject"
+ class="btn-primary" />
+ <button string="Cancel" class="btn-secondary" special="cancel" />
+ </footer>
+ </form>
+ </field>
+ </record>
- <record id="action_cancel_reason_order" model="ir.actions.act_window">
- <field name="name">Cancel Reason</field>
- <field name="res_model">cancel.reason.order</field>
- <field name="view_mode">form</field>
- <field name="target">new</field>
- </record>
+ <record id="action_cancel_reason_order" model="ir.actions.act_window">
+ <field name="name">Cancel Reason</field>
+ <field name="res_model">cancel.reason.order</field>
+ <field name="view_mode">form</field>
+ <field name="target">new</field>
+ </record>
</data>
<data>
<record id="sale_order_tree_view_inherit" model="ir.ui.view">
<field name="name">Sale Order</field>
<field name="model">sale.order</field>
- <field name="inherit_id" ref="sale.view_quotation_tree_with_onboarding"/>
+ <field name="inherit_id" ref="sale.view_quotation_tree_with_onboarding" />
<field name="arch" type="xml">
<field name="state" position="after">
<field name="approval_status" />
- <field name="client_order_ref"/>
- <field name="payment_type" optional="hide"/>
- <field name="payment_status" optional="hide"/>
- <field name="pareto_status" optional="hide"/>
- <field name="shipping_method_picking" optional="hide"/>
+ <field name="client_order_ref" />
+ <field name="payment_type" optional="hide" />
+ <field name="payment_status" optional="hide" />
+ <field name="pareto_status" optional="hide" />
+ <field name="shipping_method_picking" optional="hide" />
</field>
</field>
</record>
<record id="sales_order_tree_view_inherit" model="ir.ui.view">
<field name="name">Sale Order</field>
<field name="model">sale.order</field>
- <field name="inherit_id" ref="sale.view_order_tree"/>
+ <field name="inherit_id" ref="sale.view_order_tree" />
<field name="arch" type="xml">
<field name="state" position="after">
<field name="approval_status" />
- <field name="client_order_ref"/>
- <field name="so_status"/>
- <field name="date_status_done"/>
- <field name="date_kirim_ril"/>
- <field name="date_driver_departure"/>
- <field name="date_driver_arrival"/>
- <field name="payment_type" optional="hide"/>
- <field name="payment_status" optional="hide"/>
- <field name="pareto_status" optional="hide"/>
+ <field name="client_order_ref" />
+ <field name="so_status" />
+ <field name="date_status_done" />
+ <field name="date_kirim_ril" />
+ <field name="date_driver_departure" />
+ <field name="date_driver_arrival" />
+ <field name="payment_type" optional="hide" />
+ <field name="payment_status" optional="hide" />
+ <field name="pareto_status" optional="hide" />
</field>
</field>
</record>
<record id="sale_order_multi_update_ir_actions_server" model="ir.actions.server">
<field name="name">Mark As Cancel</field>
- <field name="model_id" ref="sale.model_sale_order"/>
- <field name="binding_model_id" ref="sale.model_sale_order"/>
+ <field name="model_id" ref="sale.model_sale_order" />
+ <field name="binding_model_id" ref="sale.model_sale_order" />
<field name="binding_view_types">form,list</field>
<field name="state">code</field>
<field name="code">action = records.open_form_multi_update_state()</field>
@@ -365,46 +417,81 @@
<record id="sale_order_update_multi_actions_server" model="ir.actions.server">
<field name="name">Mark As Completed</field>
- <field name="model_id" ref="sale.model_sale_order"/>
- <field name="binding_model_id" ref="sale.model_sale_order"/>
+ <field name="model_id" ref="sale.model_sale_order" />
+ <field name="binding_model_id" ref="sale.model_sale_order" />
<field name="state">code</field>
<field name="code">action = records.open_form_multi_update_status()</field>
</record>
<record id="mail_template_sale_order_web_approve_notification" model="mail.template">
<field name="name">Sale Order: Web Approve Notification</field>
- <field name="model_id" ref="indoteknik_custom.model_sale_order"/>
+ <field name="model_id" ref="indoteknik_custom.model_sale_order" />
<field name="subject">Permintaan Persetujuan Pesanan ${object.name} di Indoteknik.com</field>
<field name="email_from">sales@indoteknik.com</field>
<field name="email_to">${object.partner_id.email | safe}</field>
<field name="email_cc">${object.partner_id.get_approve_partner_ids("email_comma_sep")}</field>
<field name="body_html" type="html">
- <table border="0" cellpadding="0" cellspacing="0" style="padding: 16px 0; background-color: #F1F1F1; font-family:Inter, Helvetica, Verdana, Arial,sans-serif; line-height: 24px; color: #454748; width: 100%; border-collapse:separate;">
- <tr><td align="center">
- <table border="0" cellpadding="0" cellspacing="0" width="590" style="font-size: 13px; padding: 16px; background-color: white; color: #454748; border-collapse:separate;">
- <tbody>
- <tr>
- <td align="center" style="min-width: 590px;">
- <table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
- <tr><td style="padding-bottom: 24px;">Dear ${(object.partner_id.get_main_parent()).name},</td></tr>
+ <table border="0" cellpadding="0" cellspacing="0"
+ style="padding: 16px 0; background-color: #F1F1F1; font-family:Inter, Helvetica, Verdana, Arial,sans-serif; line-height: 24px; color: #454748; width: 100%; border-collapse:separate;">
+ <tr>
+ <td align="center">
+ <table border="0" cellpadding="0" cellspacing="0" width="590"
+ style="font-size: 13px; padding: 16px; background-color: white; color: #454748; border-collapse:separate;">
+ <tbody>
+ <tr>
+ <td align="center" style="min-width: 590px;">
+ <table border="0" cellpadding="0" cellspacing="0"
+ width="590"
+ style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
+ <tr>
+ <td style="padding-bottom: 24px;">
+ Dear
+ ${(object.partner_id.get_main_parent()).name},</td>
+ </tr>
- <tr><td style="padding-bottom: 16px;">Ini adalah konfirmasi pesanan dari ${object.partner_id.name | safe} untuk nomor pesanan ${object.name} yang memerlukan persetujuan agar dapat diproses.</td></tr>
- <tr><td style="padding-bottom: 16px;">
- <a href="https://indoteknik.com/my/quotations/${object.id}" style="color: white; background-color: #C53030; border: none; border-radius: 6px; padding: 4px 8px; width: fit-content; display: block;">
- Lihat Pesanan
- </a>
- </td></tr>
- <tr><td style="padding-bottom: 16px;">Mohon segera melakukan tinjauan terhadap pesanan ini dan memberikan persetujuan. Terima kasih atas perhatian dan kerjasama Anda. Kami berharap dapat segera melanjutkan proses pesanan ini setelah mendapatkan persetujuan Anda.</td></tr>
+ <tr>
+ <td style="padding-bottom: 16px;">Ini adalah
+ konfirmasi pesanan dari
+ ${object.partner_id.name | safe} untuk nomor
+ pesanan ${object.name} yang memerlukan
+ persetujuan agar dapat diproses.</td>
+ </tr>
+ <tr>
+ <td style="padding-bottom: 16px;">
+ <a
+ href="https://indoteknik.com/my/quotations/${object.id}"
+ style="color: white; background-color: #C53030; border: none; border-radius: 6px; padding: 4px 8px; width: fit-content; display: block;">
+ Lihat Pesanan
+ </a>
+ </td>
+ </tr>
+ <tr>
+ <td style="padding-bottom: 16px;">Mohon segera
+ melakukan tinjauan terhadap pesanan ini dan
+ memberikan persetujuan. Terima kasih atas
+ perhatian dan kerjasama Anda. Kami berharap
+ dapat segera melanjutkan proses pesanan ini
+ setelah mendapatkan persetujuan Anda.</td>
+ </tr>
- <tr><td style="padding-bottom: 2px;">Hormat kami,</td></tr>
- <tr><td style="padding-bottom: 2px;">PT. Indoteknik Dotcom Gemilang</td></tr>
- <tr><td style="padding-bottom: 2px;">sales@indoteknik.com</td></tr>
- </table>
- </td>
- </tr>
- </tbody>
- </table>
- </td></tr>
+ <tr>
+ <td style="padding-bottom: 2px;">Hormat kami,</td>
+ </tr>
+ <tr>
+ <td style="padding-bottom: 2px;">PT. Indoteknik
+ Dotcom Gemilang</td>
+ </tr>
+ <tr>
+ <td style="padding-bottom: 2px;">
+ sales@indoteknik.com</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
</table>
</field>
</record>
@@ -416,11 +503,11 @@
<field name="model">sales.order.purchase.match</field>
<field name="arch" type="xml">
<tree editable="top" create="false" delete="false">
- <field name="purchase_order_id" readonly="1"/>
- <field name="purchase_line_id" readonly="1"/>
- <field name="product_id" readonly="1"/>
- <field name="qty_so" readonly="1"/>
- <field name="qty_po" readonly="1"/>
+ <field name="purchase_order_id" readonly="1" />
+ <field name="purchase_line_id" readonly="1" />
+ <field name="product_id" readonly="1" />
+ <field name="qty_so" readonly="1" />
+ <field name="qty_po" readonly="1" />
</tree>
</field>
</record>
@@ -432,9 +519,9 @@
<field name="model">sales.order.koli</field>
<field name="arch" type="xml">
<tree editable="top" create="false" delete="false">
- <field name="koli_id" readonly="1"/>
- <field name="picking_id" readonly="1"/>
- <field name="state" readonly="1"/>
+ <field name="koli_id" readonly="1" />
+ <field name="picking_id" readonly="1" />
+ <field name="state" readonly="1" />
</tree>
</field>
</record>
@@ -443,32 +530,32 @@
<data>
</data>
- <record id="sales_order_fulfillment_v2_tree" model="ir.ui.view">
- <field name="name">sales.order.fulfillment.v2.tree</field>
- <field name="model">sales.order.fulfillment.v2</field>
- <field name="arch" type="xml">
- <tree editable="top" create="false">
- <field name="product_id" readonly="1"/>
- <field name="so_qty" readonly="1" optional="show"/>
- <field name="reserved_stock_qty" readonly="1" optional="show"/>
- <field name="delivered_qty" readonly="1" optional="hide"/>
- <field name="po_ids" widget="many2many_tags" readonly="1" optional="show"/>
- <field name="po_qty" readonly="1" optional="show"/>
- <field name="received_qty" readonly="1" optional="show"/>
- <field name="purchaser" readonly="1" optional="hide"/>
- </tree>
- </field>
- </record>
+ <record id="sales_order_fulfillment_v2_tree" model="ir.ui.view">
+ <field name="name">sales.order.fulfillment.v2.tree</field>
+ <field name="model">sales.order.fulfillment.v2</field>
+ <field name="arch" type="xml">
+ <tree editable="top" create="false">
+ <field name="product_id" readonly="1" />
+ <field name="so_qty" readonly="1" optional="show" />
+ <field name="reserved_stock_qty" readonly="1" optional="show" />
+ <field name="delivered_qty" readonly="1" optional="hide" />
+ <field name="po_ids" widget="many2many_tags" readonly="1" optional="show" />
+ <field name="po_qty" readonly="1" optional="show" />
+ <field name="received_qty" readonly="1" optional="show" />
+ <field name="purchaser" readonly="1" optional="hide" />
+ </tree>
+ </field>
+ </record>
<data>
<record id="sales_order_fullfillmet_tree" model="ir.ui.view">
<field name="name">sales.order.fullfillment.tree</field>
<field name="model">sales.order.fullfillment</field>
<field name="arch" type="xml">
<tree editable="top" create="false">
- <field name="product_id" readonly="1"/>
- <field name="reserved_from" readonly="1"/>
- <field name="qty_fullfillment" readonly="1"/>
- <field name="user_id" readonly="1"/>
+ <field name="product_id" readonly="1" />
+ <field name="reserved_from" readonly="1" />
+ <field name="qty_fullfillment" readonly="1" />
+ <field name="user_id" readonly="1" />
</tree>
</field>
</record>
@@ -480,9 +567,9 @@
<field name="model">sales.order.reject</field>
<field name="arch" type="xml">
<tree editable="top" create="false">
- <field name="product_id" readonly="1"/>
- <field name="qty_reject" readonly="1"/>
- <field name="reason_reject" readonly="1"/>
+ <field name="product_id" readonly="1" />
+ <field name="qty_reject" readonly="1" />
+ <field name="reason_reject" readonly="1" />
</tree>
</field>
</record>
@@ -491,8 +578,8 @@
<data>
<record id="sale_order_multi_create_uangmuka_ir_actions_server" model="ir.actions.server">
<field name="name">Uang Muka</field>
- <field name="model_id" ref="sale.model_sale_order"/>
- <field name="binding_model_id" ref="sale.model_sale_order"/>
+ <field name="model_id" ref="sale.model_sale_order" />
+ <field name="binding_model_id" ref="sale.model_sale_order" />
<field name="state">code</field>
<field name="code">action = records.open_form_multi_create_uang_muka()</field>
</record>
@@ -501,66 +588,84 @@
<data>
<record id="mail_template_sale_order_notification_to_salesperson" model="mail.template">
<field name="name">Sale Order: Notification to Salesperson</field>
- <field name="model_id" ref="sale.model_sale_order"/>
+ <field name="model_id" ref="sale.model_sale_order" />
<field name="subject">Konsolidasi Pengiriman</field>
<field name="email_from">sales@indoteknik.com</field>
<field name="email_to">${object.user_id.login | safe}</field>
<field name="body_html" type="html">
- <table border="0" cellpadding="0" cellspacing="0" style="padding-top: 16px; background-color: #F1F1F1; font-family:Inter, Helvetica, Verdana, Arial,sans-serif; line-height: 24px; color: #454748; width: 100%; border-collapse:separate;">
- <tr><td align="center">
- <table border="0" cellpadding="0" cellspacing="0" width="590" style="font-size: 13px; padding: 16px; background-color: white; color: #454748; border-collapse:separate;">
- <!-- HEADER -->
- <tbody>
- <tr>
- <td align="center" style="min-width: 590px;">
- <table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
- <tr>
- <td valign="middle">
- <span></span>
- </td>
- </tr>
- </table>
- </td>
- </tr>
- <!-- CONTENT -->
- <tr>
- <td align="center" style="min-width: 590px;">
- <table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
- <tr><td style="padding-bottom: 24px;">Dear ${salesperson_name},</td></tr>
-
- <tr><td style="padding-bottom: 16px;">Terdapat pesanan dari BP ${business_partner} untuk site ${site} dengan total belanja ${sum_total_amount} dari list SO dibawah ini:</td></tr>
-
- <tr>
- <td>
- <table border="1" cellpadding="5" cellspacing="0">
- <thead>
- <tr>
- <th>Nama Pesanan</th>
- <th>Nama Perusahaan Induk</th>
- <th>Nama Situs</th>
- <th>Total Pembelian</th>
- </tr>
- </thead>
- <tbody>
- ${table_content}
- </tbody>
- </table>
- </td>
- </tr>
-
- <tr>
- <td style="text-align:center;">
- <hr width="100%"
- style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;" />
- </td>
- </tr>
- </table>
- </td>
- </tr>
- <!-- CONTENT -->
- </tbody>
- </table>
- </td></tr>
+ <table border="0" cellpadding="0" cellspacing="0"
+ style="padding-top: 16px; background-color: #F1F1F1; font-family:Inter, Helvetica, Verdana, Arial,sans-serif; line-height: 24px; color: #454748; width: 100%; border-collapse:separate;">
+ <tr>
+ <td align="center">
+ <table border="0" cellpadding="0" cellspacing="0" width="590"
+ style="font-size: 13px; padding: 16px; background-color: white; color: #454748; border-collapse:separate;">
+ <!-- HEADER -->
+ <tbody>
+ <tr>
+ <td align="center" style="min-width: 590px;">
+ <table border="0" cellpadding="0" cellspacing="0"
+ width="590"
+ style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
+ <tr>
+ <td valign="middle">
+ <span></span>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <!-- CONTENT -->
+ <tr>
+ <td align="center" style="min-width: 590px;">
+ <table border="0" cellpadding="0" cellspacing="0"
+ width="590"
+ style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
+ <tr>
+ <td style="padding-bottom: 24px;">Dear
+ ${salesperson_name},</td>
+ </tr>
+
+ <tr>
+ <td style="padding-bottom: 16px;">Terdapat
+ pesanan dari BP ${business_partner} untuk
+ site ${site} dengan total belanja
+ ${sum_total_amount} dari list SO dibawah
+ ini:</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table border="1" cellpadding="5"
+ cellspacing="0">
+ <thead>
+ <tr>
+ <th>Nama Pesanan</th>
+ <th>Nama Perusahaan Induk</th>
+ <th>Nama Situs</th>
+ <th>Total Pembelian</th>
+ </tr>
+ </thead>
+ <tbody>
+ ${table_content}
+ </tbody>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td style="text-align:center;">
+ <hr width="100%"
+ style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;" />
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <!-- CONTENT -->
+ </tbody>
+ </table>
+ </td>
+ </tr>
</table>
</field>
</record>
diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml
index 4c60a496..c916f2ef 100644
--- a/indoteknik_custom/views/stock_picking.xml
+++ b/indoteknik_custom/views/stock_picking.xml
@@ -123,6 +123,7 @@
<field name="date_doc_kirim" attrs="{'readonly':[('invoice_status', '=', 'invoiced')]}"/>
<field name="summary_qty_operation"/>
<field name="count_line_operation"/>
+ <field name="linked_manual_bu_out" attrs="{'invisible': [('location_id', '=', 60)]}" domain="[('picking_type_code', '=', 'outgoing'),('state', 'not in', ['done','cancel']), ('group_id', '=', group_id)]"/>
<field name="account_id"
attrs="{
'readonly': [['state', 'in', ['done', 'cancel']]],
@@ -174,6 +175,7 @@
<group>
<field name="notee"/>
<field name="note_logistic"/>
+ <field name="note_info"/>
<field name="responsible" />
<field name="carrier_id"/>
<field name="out_code" attrs="{'invisible': [['out_code', '=', False]]}"/>
@@ -243,7 +245,8 @@
<field name="model">scan.koli</field>
<field name="arch" type="xml">
<tree editable="bottom">
- <field name="koli_id" options="{'no_create': True}" required="1" domain="[('state', '=', 'not_delivered')]"/>
+ <field name="code_koli"/>
+ <field name="koli_id" options="{'no_create': True}" domain="[('state', '=', 'not_delivered')]"/>
<field name="scan_koli_progress"/>
</tree>
</field>
@@ -254,7 +257,7 @@
<field name="model">konfirm.koli</field>
<field name="arch" type="xml">
<tree editable="bottom">
- <field name="pick_id" options="{'no_create': True}" required="1" domain="[('picking_type_code', '=', 'internal'), ('group_id', '=', parent.group_id)]"/>
+ <field name="pick_id" options="{'no_create': True}" required="1" domain="[('picking_type_code', '=', 'internal'), ('group_id', '=', parent.group_id), ('linked_manual_bu_out', '=', parent.id)]"/>
</tree>
</field>
</record>
@@ -276,8 +279,9 @@
<field name="model">check.product</field>
<field name="arch" type="xml">
<tree editable="bottom" decoration-warning="status == 'Pending'" decoration-success="status == 'Done'">
- <field name="product_id" required="1" options="{'no_create': True}"/>
- <field name="quantity" readonly="1"/>
+ <field name="code_product"/>
+ <field name="product_id"/>
+ <field name="quantity"/>
<field name="status" readonly="1"/>
</tree>
</field>
diff --git a/indoteknik_custom/views/vendor_payment_term.xml b/indoteknik_custom/views/vendor_payment_term.xml
index e0e96388..7d16b129 100644
--- a/indoteknik_custom/views/vendor_payment_term.xml
+++ b/indoteknik_custom/views/vendor_payment_term.xml
@@ -8,6 +8,8 @@
<field name="display_name"/>
<field name="name"/>
<field name="parent_id"/>
+ <field name="minimum_amount"/>
+ <field name="minimum_amount_tax"/>
<field name="property_supplier_payment_term_id"/>
</tree>
</field>
@@ -23,6 +25,8 @@
<group>
<field name="name"/>
<field name="parent_id" readonly="1"/>
+ <field name="minimum_amount"/>
+ <field name="minimum_amount_tax"/>
<field name="property_supplier_payment_term_id"/>
</group>
</group>