summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAzka Nathan <darizkyfaz@gmail.com>2025-05-14 10:21:18 +0700
committerAzka Nathan <darizkyfaz@gmail.com>2025-05-14 10:21:18 +0700
commitf9240997e9796a1149a1f8bddc48fa1ebbbbf873 (patch)
tree98f106aa0996f14f2ee0001d6c550a2b054efd5f
parent509a771b8ba6122cc308323dbe90ff4a35e4fc72 (diff)
parent285fa052180ca0ae11e0431d5cf95e795008cae9 (diff)
Merge branch 'odoo-backup' of bitbucket.org:altafixco/indoteknik-addons into odoo-backup
-rwxr-xr-xindoteknik_custom/models/sale_order.py466
-rwxr-xr-xindoteknik_custom/views/sale_order.xml498
2 files changed, 510 insertions, 454 deletions
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index 0d4fc6c3..99aa8053 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -9,6 +9,7 @@ from collections import defaultdict
_logger = logging.getLogger(__name__)
+
class CancelReasonOrder(models.TransientModel):
_name = 'cancel.reason.order'
_description = 'Wizard for Cancel Reason order'
@@ -44,7 +45,7 @@ class CancelReasonOrder(models.TransientModel):
raise UserError('Attachment bukti wajib disertakan')
order.write({'attachment_bukti': self.attachment_bukti})
order.message_post(body='Attachment Bukti Cancel',
- attachment_ids=[self.attachment_bukti.id])
+ attachment_ids=[self.attachment_bukti.id])
if self.reason_cancel == 'ganti_quotation':
if self.nomor_so_pengganti:
order.write({'nomor_so_pengganti': self.nomor_so_pengganti})
@@ -53,7 +54,8 @@ class CancelReasonOrder(models.TransientModel):
order.confirm_cancel_order()
return {'type': 'ir.actions.act_window_close'}
-
+
+
class ShippingOption(models.Model):
_name = "shipping.option"
_description = "Shipping Option"
@@ -64,6 +66,7 @@ class ShippingOption(models.Model):
etd = fields.Char(string="Estimated Delivery Time")
sale_order_id = fields.Many2one('sale.order', string="Sale Order", ondelete="cascade")
+
class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'
@@ -73,7 +76,7 @@ class SaleOrderLine(models.Model):
if line.order_id:
now = fields.Datetime.now()
- initial_reason="Product Rejected"
+ initial_reason = "Product Rejected"
# Buat lognote untuk product yang di delete
log_note = (f"<li>Product '{line.product_id.name}' rejected. </li>"
@@ -113,10 +116,12 @@ class SaleOrderLine(models.Model):
return result
+
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)
+ 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'),
@@ -127,22 +132,31 @@ class SaleOrder(models.Model):
('other', 'Other'),
], string='Metode Kirim Ke Ekspedisi', copy=False, index=True, tracking=3)
+ notes = fields.Text(string="Notes", 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')
reject_line = fields.One2many('sales.order.reject', 'sale_order_id', string='Reject Lines')
- order_sales_match_line = fields.One2many('sales.order.purchase.match', 'sales_order_id', string='Purchase Match Lines', states={'cancel': [('readonly', True)], 'done': [('readonly', True)]}, copy=True)
- total_margin = fields.Float('Total Margin', compute='_compute_total_margin', help="Total Margin in Sales Order Header")
- total_before_margin = fields.Float('Total Before Margin', compute='_compute_total_before_margin', help="Total Margin in Sales Order Header")
- total_percent_margin = fields.Float('Total Percent Margin', compute='_compute_total_percent_margin', help="Total % Margin in Sales Order Header")
- total_margin_excl_third_party = fields.Float('Before Margin', help="Before Margin in Sales Order Header", compute='_compute_total_margin_excl_third_party')
+ order_sales_match_line = fields.One2many('sales.order.purchase.match', 'sales_order_id',
+ string='Purchase Match Lines',
+ states={'cancel': [('readonly', True)], 'done': [('readonly', True)]},
+ copy=True)
+ total_margin = fields.Float('Total Margin', compute='_compute_total_margin',
+ help="Total Margin in Sales Order Header")
+ total_before_margin = fields.Float('Total Before Margin', compute='_compute_total_before_margin',
+ help="Total Margin in Sales Order Header")
+ total_percent_margin = fields.Float('Total Percent Margin', compute='_compute_total_percent_margin',
+ help="Total % Margin in Sales Order Header")
+ total_margin_excl_third_party = fields.Float('Before Margin', help="Before Margin in Sales Order Header",
+ compute='_compute_total_margin_excl_third_party')
approval_status = fields.Selection([
('pengajuan1', 'Approval Manager'),
('pengajuan2', 'Approval Pimpinan'),
('approved', 'Approved'),
], string='Approval Status', readonly=True, copy=False, index=True, tracking=3)
carrier_id = fields.Many2one('delivery.carrier', string='Shipping Method', tracking=3)
- have_visit_service = fields.Boolean(string='Have Visit Service', compute='_have_visit_service', help='To compute is customer get visit service')
+ have_visit_service = fields.Boolean(string='Have Visit Service', compute='_have_visit_service',
+ help='To compute is customer get visit service')
delivery_amt = fields.Float(string='Delivery Amt', copy=False)
shipping_cost_covered = fields.Selection([
('indoteknik', 'Indoteknik'),
@@ -152,7 +166,8 @@ class SaleOrder(models.Model):
('indoteknik', 'Indoteknik'),
('customer', 'Customer')
], string='Shipping Paid by', help='Siapa yang talangin dulu Biaya ekspedisi-nya?', copy=False, tracking=3)
- sales_tax_id = fields.Many2one('account.tax', string='Tax', domain=['|', ('active', '=', False), ('active', '=', True)])
+ sales_tax_id = fields.Many2one('account.tax', string='Tax',
+ domain=['|', ('active', '=', False), ('active', '=', True)])
have_outstanding_invoice = fields.Boolean('Have Outstanding Invoice', compute='_have_outstanding_invoice')
have_outstanding_picking = fields.Boolean('Have Outstanding Picking', compute='_have_outstanding_picking')
have_outstanding_po = fields.Boolean('Have Outstanding PO', compute='_have_outstanding_po')
@@ -173,9 +188,14 @@ class SaleOrder(models.Model):
('sebagian', 'Sebagian Diproses'),
('menunggu', 'Menunggu Diproses'),
], copy=False)
- partner_purchase_order_name = fields.Char(string='Nama PO Customer', copy=False, help="Nama purchase order customer, diisi oleh customer melalui website.", tracking=3)
- partner_purchase_order_description = fields.Text(string='Keterangan PO Customer', copy=False, help="Keterangan purchase order customer, diisi oleh customer melalui website.", tracking=3)
- partner_purchase_order_file = fields.Binary(string='File PO Customer', copy=False, help="File purchase order customer, diisi oleh customer melalui website.")
+ partner_purchase_order_name = fields.Char(string='Nama PO Customer', copy=False,
+ help="Nama purchase order customer, diisi oleh customer melalui website.",
+ tracking=3)
+ partner_purchase_order_description = fields.Text(string='Keterangan PO Customer', copy=False,
+ help="Keterangan purchase order customer, diisi oleh customer melalui website.",
+ tracking=3)
+ partner_purchase_order_file = fields.Binary(string='File PO Customer', copy=False,
+ help="File purchase order customer, diisi oleh customer melalui website.")
payment_status = fields.Selection([
('pending', 'Pending'),
('capture', 'Capture'),
@@ -189,17 +209,22 @@ class SaleOrder(models.Model):
('partial_refund', 'Partial Refund'),
('partial_chargeback', 'Partial Chargeback'),
('authorize', 'Authorize'),
- ], tracking=True, string='Payment Status', help='Payment Gateway Status / Midtrans / Web, https://docs.midtrans.com/en/after-payment/status-cycle')
- date_doc_kirim = fields.Datetime(string='Tanggal Kirim di SJ', help="Tanggal Kirim di cetakan SJ yang terakhir, tidak berpengaruh ke Accounting")
+ ], tracking=True, string='Payment Status',
+ help='Payment Gateway Status / Midtrans / Web, https://docs.midtrans.com/en/after-payment/status-cycle')
+ date_doc_kirim = fields.Datetime(string='Tanggal Kirim di SJ',
+ help="Tanggal Kirim di cetakan SJ yang terakhir, tidak berpengaruh ke Accounting")
payment_type = fields.Char(string='Payment Type', help='Jenis pembayaran dengan Midtrans')
gross_amount = fields.Float(string='Gross Amount', help='Jumlah pembayaran yang dilakukan dengan Midtrans')
notification = fields.Char(string='Notification', help='Dapat membantu error dari approval')
delivery_service_type = fields.Char(string='Delivery Service Type', help='data dari rajaongkir')
- grand_total = fields.Monetary(string='Grand Total', help='Amount total + amount delivery', compute='_compute_grand_total')
- payment_link_midtrans = fields.Char(string='Payment Link', help='Url payment yg digenerate oleh midtrans, harap diserahkan ke customer agar dapat dilakukan pembayaran secara mandiri')
+ grand_total = fields.Monetary(string='Grand Total', help='Amount total + amount delivery',
+ compute='_compute_grand_total')
+ payment_link_midtrans = fields.Char(string='Payment Link',
+ help='Url payment yg digenerate oleh midtrans, harap diserahkan ke customer agar dapat dilakukan pembayaran secara mandiri')
payment_qr_code = fields.Binary("Payment QR Code")
- due_id = fields.Many2one('due.extension', string="Due Extension", readonly=True, tracking=True)
- vendor_approval_id = fields.Many2many('vendor.approval', string="Vendor Approval", readonly=True, tracking=True, copy=False)
+ due_id = fields.Many2one('due.extension', string="Due Extension", readonly=True, tracking=True)
+ vendor_approval_id = fields.Many2many('vendor.approval', string="Vendor Approval", readonly=True, tracking=True,
+ copy=False)
customer_type = fields.Selection([
('pkp', 'PKP'),
('nonpkp', 'Non PKP')
@@ -239,8 +264,10 @@ class SaleOrder(models.Model):
use_button = fields.Boolean(string='Using Calculate Selling Price', copy=False)
unreserve_id = fields.Many2one('stock.picking', 'Unreserve Picking')
voucher_shipping_id = fields.Many2one(comodel_name='voucher', string='Voucher Shipping', copy=False)
- margin_after_delivery_purchase = fields.Float(string='Margin After Delivery Purchase', compute='_compute_margin_after_delivery_purchase')
- percent_margin_after_delivery_purchase = fields.Float(string='% Margin After Delivery Purchase', compute='_compute_margin_after_delivery_purchase')
+ margin_after_delivery_purchase = fields.Float(string='Margin After Delivery Purchase',
+ compute='_compute_margin_after_delivery_purchase')
+ percent_margin_after_delivery_purchase = fields.Float(string='% Margin After Delivery Purchase',
+ compute='_compute_margin_after_delivery_purchase')
purchase_delivery_amt = fields.Float(string='Purchase Delivery Amount', compute='_compute_purchase_delivery_amount')
type_promotion = fields.Char(string='Type Promotion', compute='_compute_type_promotion')
partner_invoice_id = fields.Many2one(
@@ -254,11 +281,11 @@ class SaleOrder(models.Model):
'res.partner', string='Delivery Address', readonly=True, required=True,
states={'draft': [('readonly', False)], 'sent': [('readonly', False)], 'sale': [('readonly', False)]},
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", tracking=True)
-
+
payment_term_id = fields.Many2one(
'account.payment.term', string='Payment Terms', check_company=True, # Unrequired company
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", tracking=True)
-
+
total_weight = fields.Float(string='Total Weight', compute='_compute_total_weight')
pareto_status = fields.Selection([
('PR', 'Pareto Repeating'),
@@ -275,7 +302,7 @@ class SaleOrder(models.Model):
copy=False
)
shipping_method_picking = fields.Char(string='Shipping Method Picking', compute='_compute_shipping_method_picking')
-
+
reason_cancel = fields.Selection([
('harga_terlalu_mahal', 'Harga barang terlalu mahal'),
('harga_web_tidak_valid', 'Harga web tidak valid'),
@@ -296,7 +323,8 @@ class SaleOrder(models.Model):
string="Attachment Bukti Cancel", readonly=False,
)
nomor_so_pengganti = fields.Char(string='Nomor SO Pengganti', copy=False, tracking=3)
- shipping_option_id = fields.Many2one("shipping.option", string="Selected Shipping Option", domain="['|', ('sale_order_id', '=', False), ('sale_order_id', '=', id)]")
+ shipping_option_id = fields.Many2one("shipping.option", string="Selected Shipping Option",
+ domain="['|', ('sale_order_id', '=', False), ('sale_order_id', '=', id)]")
hold_outgoing = fields.Boolean('Hold Outgoing SO', tracking=3)
state_ask_cancel = fields.Selection([
('hold', 'Hold'),
@@ -355,7 +383,7 @@ class SaleOrder(models.Model):
tax_sets.add(tax_ids)
if len(tax_sets) > 1:
raise ValidationError("Semua produk dalam Sales Order harus memiliki kombinasi pajak yang sama.")
-
+
# @api.constrains('fee_third_party', 'delivery_amt', 'biaya_lain_lain')
# def _check_total_margin_excl_third_party(self):
# for rec in self:
@@ -403,14 +431,14 @@ class SaleOrder(models.Model):
def action_indoteknik_estimate_shipping(self):
if not self.real_shipping_id.kota_id.is_jabodetabek:
raise UserError('Estimasi ongkir hanya bisa dilakukan di kota Jabodetabek')
-
+
total_weight = 0
missing_weight_products = []
for line in self.order_line:
if line.weight > 0:
total_weight += line.weight * line.product_uom_qty
- line.product_id.weight = line.weight
+ line.product_id.weight = line.weight
else:
missing_weight_products.append(line.product_id.name)
@@ -420,10 +448,10 @@ class SaleOrder(models.Model):
if total_weight == 0:
raise UserError("Tidak dapat mengestimasi ongkir tanpa berat yang valid.")
-
+
if total_weight < 10:
total_weight = 10
-
+
self.delivery_amt = total_weight * 3000
shipping_option = self.env["shipping.option"].create({
@@ -456,7 +484,7 @@ class SaleOrder(models.Model):
for line in self.order_line:
if line.weight > 0:
total_weight += line.weight * line.product_uom_qty
- line.product_id.weight = line.weight
+ line.product_id.weight = line.weight
else:
missing_weight_products.append(line.product_id.name)
@@ -481,11 +509,11 @@ class SaleOrder(models.Model):
etd = cost_detail['cost'][0]['etd']
value = cost_detail['cost'][0]['value']
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({
"name": service,
@@ -495,22 +523,20 @@ class SaleOrder(models.Model):
"sale_order_id": self.id,
})
-
self.shipping_option_id = self.env["shipping.option"].search([('sale_order_id', '=', self.id)], limit=1).id
_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])}",
+ 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'
@@ -532,7 +558,7 @@ class SaleOrder(models.Model):
if response.status_code == 200:
return response.json()
return None
-
+
def _normalize_city_name(self, city_name):
city_name = city_name.lower()
@@ -552,7 +578,7 @@ class SaleOrder(models.Model):
}
normalized_city_name = self._normalize_city_name(city_name)
-
+
response = requests.get(url, headers=headers)
if response.status_code == 200:
city_data = response.json()
@@ -566,7 +592,7 @@ class SaleOrder(models.Model):
headers = {
'key': '9b1310f644056d84d60b0af6bb21611a',
}
-
+
response = requests.get(url, headers=headers)
if response.status_code == 200:
subdistrict_data = response.json()
@@ -578,15 +604,15 @@ class SaleOrder(models.Model):
return subdistrict['subdistrict_id']
return None
-
def _compute_type_promotion(self):
for rec in self:
promotion_types = []
for promotion in rec.order_promotion_ids:
for line_program in promotion.program_line_id:
if line_program.promotion_type:
- promotion_types.append(dict(line_program._fields['promotion_type'].selection).get(line_program.promotion_type))
-
+ promotion_types.append(
+ dict(line_program._fields['promotion_type'].selection).get(line_program.promotion_type))
+
rec.type_promotion = ', '.join(sorted(set(promotion_types)))
def _compute_purchase_delivery_amount(self):
@@ -610,11 +636,14 @@ class SaleOrder(models.Model):
delivery_amt = order.delivery_amt
else:
delivery_amt = 0
- order.percent_margin_after_delivery_purchase = round((order.margin_after_delivery_purchase / (order.amount_untaxed-delivery_amt-order.fee_third_party-order.biaya_lain_lain)) * 100, 2)
+ order.percent_margin_after_delivery_purchase = round((order.margin_after_delivery_purchase / (
+ order.amount_untaxed - delivery_amt - order.fee_third_party - order.biaya_lain_lain)) * 100, 2)
def _compute_date_kirim(self):
for rec in self:
- 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)
+ 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
@@ -626,54 +655,55 @@ class SaleOrder(models.Model):
'so_ids': [x.id for x in self]
}
return action
-
+
def _compute_fullfillment(self):
for rec in self:
- # rec.fullfillment_line.unlink()
- #
- # for line in rec.order_line:
- # line._compute_reserved_from()
+ # rec.fullfillment_line.unlink()
+ #
+ # for line in rec.order_line:
+ # line._compute_reserved_from()
rec.compute_fullfillment = True
@api.depends('date_order', 'estimated_arrival_days', 'state', 'estimated_arrival_days_start')
def _compute_eta_date(self):
- current_date = datetime.now().date()
- for rec in self:
- if rec.date_order and rec.state not in ['cancel'] and rec.estimated_arrival_days and rec.estimated_arrival_days_start:
+ current_date = datetime.now().date()
+ for rec in self:
+ if rec.date_order and rec.state not in [
+ 'cancel'] and rec.estimated_arrival_days and rec.estimated_arrival_days_start:
rec.eta_date = current_date + timedelta(days=rec.estimated_arrival_days)
rec.eta_date_start = current_date + timedelta(days=rec.estimated_arrival_days_start)
else:
rec.eta_date = False
rec.eta_date_start = False
-
-
- def get_days_until_next_business_day(self,start_date=None, *args, **kwargs):
+
+ def get_days_until_next_business_day(self, start_date=None, *args, **kwargs):
today = start_date or datetime.today().date()
offset = 0 # Counter jumlah hari yang ditambahkan
holiday = self.env['hr.public.holiday']
- while True :
+ while True:
today += timedelta(days=1)
offset += 1
-
+
if today.weekday() >= 5:
continue
is_holiday = holiday.search([("start_date", "=", today)])
if is_holiday:
continue
-
+
break
return offset
-
+
def calculate_sla_by_vendor(self, products):
product_ids = products.mapped('product_id.id') # Kumpulkan semua ID produk
include_instant = True # Default True, tetapi bisa menjadi False
# Cek apakah SEMUA produk memiliki qty_free_bandengan >= qty_needed
- all_fast_products = all(product.product_id.qty_free_bandengan >= product.product_uom_qty for product in products)
+ all_fast_products = all(
+ product.product_id.qty_free_bandengan >= product.product_uom_qty for product in products)
if all_fast_products:
return {'slatime': 1, 'include_instant': include_instant}
@@ -683,7 +713,7 @@ class SaleOrder(models.Model):
('is_winner', '=', True)
])
- max_slatime = 1
+ max_slatime = 1
for vendor in vendors:
vendor_sla = self.env['vendor.sla'].search([('id_vendor', '=', vendor.vendor_id.id)], limit=1)
@@ -692,26 +722,26 @@ class SaleOrder(models.Model):
if vendor_sla.unit == 'hari':
vendor_duration = vendor_sla.duration * 24 * 60
include_instant = False
- else :
+ else:
vendor_duration = vendor_sla.duration * 60
include_instant = True
-
+
estimation_sla = (1 * 24 * 60) + vendor_duration
estimation_sla_days = estimation_sla / (24 * 60)
slatime = math.ceil(estimation_sla_days)
-
+
max_slatime = max(max_slatime, slatime)
return {'slatime': max_slatime, 'include_instant': include_instant}
-
+
def _calculate_etrts_date(self):
for rec in self:
if not rec.date_order:
rec.expected_ready_to_ship = False
return
-
+
current_date = datetime.now().date()
-
+
max_slatime = 1 # Default SLA jika tidak ada
slatime = self.calculate_sla_by_vendor(rec.order_line)
max_slatime = max(max_slatime, slatime['slatime'])
@@ -719,29 +749,28 @@ class SaleOrder(models.Model):
sum_days = max_slatime + self.get_days_until_next_business_day(current_date) - 1
if not rec.estimated_arrival_days:
rec.estimated_arrival_days = sum_days
-
+
eta_date = current_date + timedelta(days=sum_days)
rec.commitment_date = eta_date
rec.expected_ready_to_ship = eta_date
-
- @api.depends("order_line.product_id", "date_order")
- def _compute_etrts_date(self): #Function to calculate Estimated Ready To Ship Date
+
+ @api.depends("order_line.product_id", "date_order")
+ def _compute_etrts_date(self): # Function to calculate Estimated Ready To Ship Date
self._calculate_etrts_date()
-
-
+
def _validate_expected_ready_ship_date(self):
for rec in self:
if rec.expected_ready_to_ship and rec.commitment_date:
current_date = datetime.now().date()
# Hanya membandingkan tanggal saja, tanpa jam
expected_date = rec.expected_ready_to_ship.date()
-
+
max_slatime = 1 # Default SLA jika tidak ada
slatime = self.calculate_sla_by_vendor(rec.order_line)
max_slatime = max(max_slatime, slatime['slatime'])
sum_days = max_slatime + self.get_days_until_next_business_day(current_date) - 1
eta_minimum = current_date + timedelta(days=sum_days)
-
+
if expected_date < eta_minimum:
rec.expected_ready_to_ship = eta_minimum
raise ValidationError(
@@ -750,16 +779,16 @@ class SaleOrder(models.Model):
)
else:
rec.commitment_date = rec.expected_ready_to_ship
-
-
- @api.onchange('expected_ready_to_ship') #Hangle Onchange form Expected Ready to Ship
+
+ @api.onchange('expected_ready_to_ship') # Hangle Onchange form Expected Ready to Ship
def _onchange_expected_ready_ship_date(self):
self._validate_expected_ready_ship_date()
def _set_etrts_date(self):
for order in self:
if order.state in ('done', 'cancel', 'sale'):
- raise UserError(_("You cannot change the Estimated Ready To Ship Date on a done, sale or cancelled order."))
+ raise UserError(
+ _("You cannot change the Estimated Ready To Ship Date on a done, sale or cancelled order."))
# order.move_lines.write({'estimated_ready_ship_date': order.estimated_ready_ship_date})
def _prepare_invoice(self):
@@ -771,10 +800,12 @@ class SaleOrder(models.Model):
self.ensure_one()
journal = self.env['account.move'].with_context(default_move_type='out_invoice')._get_default_journal()
if not journal:
- raise UserError(_('Please define an accounting sales journal for the company %s (%s).') % (self.company_id.name, self.company_id.id))
+ raise UserError(
+ _('Please define an accounting sales journal for the company %s (%s).') % (self.company_id.name,
+ self.company_id.id))
parent_id = self.partner_id.parent_id
- parent_id = parent_id if parent_id else self.partner_id
+ parent_id = parent_id if parent_id else self.partner_id
invoice_vals = {
'ref': self.client_order_ref or '',
@@ -791,7 +822,8 @@ class SaleOrder(models.Model):
'partner_id': parent_id.id,
'partner_shipping_id': parent_id.id,
'real_invoice_id': self.real_invoice_id.id,
- 'fiscal_position_id': (self.fiscal_position_id or self.fiscal_position_id.get_fiscal_position(self.partner_invoice_id.id)).id,
+ 'fiscal_position_id': (self.fiscal_position_id or self.fiscal_position_id.get_fiscal_position(
+ self.partner_invoice_id.id)).id,
'partner_bank_id': self.company_id.partner_id.bank_ids[:1].id,
'journal_id': journal.id, # company comes from the journal
'invoice_origin': self.name,
@@ -807,10 +839,10 @@ class SaleOrder(models.Model):
def _validate_email(self):
rule_regex = self.env['ir.config_parameter'].sudo().get_param('sale.order.validate_email') or ''
pattern = rf'^{rule_regex}$'
-
+
if self.email and not re.match(pattern, self.email):
raise UserError('Email yang anda input kurang valid')
-
+
# @api.constrains('delivery_amt', 'carrier_id', 'shipping_cost_covered')
def _validate_delivery_amt(self):
is_indoteknik = self.carrier_id.id == 1 or self.shipping_cost_covered == 'indoteknik'
@@ -822,13 +854,14 @@ class SaleOrder(models.Model):
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.')
+ raise UserError(
+ 'Untuk Kurir Indoteknik Delivery, estimasi ongkos kirim belum memenuhi tarif minimum.')
else:
- raise UserError('Untuk Shipping Covered Indoteknik, estimasi ongkos kirim belum memenuhi tarif minimum.')
-
+ 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', []):
@@ -837,7 +870,6 @@ class SaleOrder(models.Model):
# 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:
raise UserError('Hanya Finance Accounting yang dapat klik tombol ini')
@@ -878,14 +910,14 @@ class SaleOrder(models.Model):
'sale_ids': [x.id for x in self]
}
return action
-
+
def open_form_multi_update_state(self):
action = self.env['ir.actions.act_window']._for_xml_id('indoteknik_custom.action_quotation_so_multi_update')
action['context'] = {
'quotation_ids': [x.id for x in self]
}
return action
-
+
def action_multi_update_invoice_status(self):
for sale in self:
sale.update({
@@ -898,7 +930,7 @@ class SaleOrder(models.Model):
for line in order.order_line:
total += line.vendor_subtotal
order.purchase_total = total
-
+
def check_data_real_delivery_address(self):
real_delivery_address = self.real_shipping_id
@@ -918,8 +950,8 @@ class SaleOrder(models.Model):
def generate_payment_link_midtrans_sales_order(self):
# midtrans_url = 'https://app.sandbox.midtrans.com/snap/v1/transactions' # dev - sandbox
# midtrans_auth = 'Basic U0ItTWlkLXNlcnZlci1uLVY3ZDJjMlpCMFNWRUQyOU95Q1dWWXA6' # dev - sandbox
- midtrans_url = 'https://app.midtrans.com/snap/v1/transactions' # production
- midtrans_auth = 'Basic TWlkLXNlcnZlci1SbGMxZ2gzWGpSVW5scl9JblZzTV9OTnU6' # production
+ midtrans_url = 'https://app.midtrans.com/snap/v1/transactions' # production
+ midtrans_auth = 'Basic TWlkLXNlcnZlci1SbGMxZ2gzWGpSVW5scl9JblZzTV9OTnU6' # production
so_number = self.name
so_number = so_number.replace('/', '-')
so_grandtotal = math.floor(self.grand_total)
@@ -934,7 +966,8 @@ class SaleOrder(models.Model):
if check_response.status_code == 200:
status_response = check_response.json()
- if status_response.get('transaction_status') == 'expire' or status_response.get('transaction_status') == 'cancel':
+ if status_response.get('transaction_status') == 'expire' or status_response.get(
+ 'transaction_status') == 'cancel':
so_number = so_number + '-cpl'
json_data = {
@@ -982,8 +1015,7 @@ class SaleOrder(models.Model):
if line.product_id.type == 'product':
line_no += 1
line.line_no = line_no
-
-
+
def write(self, vals):
if 'carrier_id' in vals:
for picking in self.picking_ids:
@@ -996,7 +1028,7 @@ class SaleOrder(models.Model):
('state', 'in', so_state),
('so_status', '!=', 'terproses'),
])
-
+
for sale in sales:
picking_states = ['draft', 'assigned', 'confirmed', 'waiting']
have_outstanding_pick = any(x.state in picking_states for x in sale.picking_ids)
@@ -1010,16 +1042,16 @@ class SaleOrder(models.Model):
sale.so_status = 'terproses'
else:
sale.so_status = 'menunggu'
-
+
for picking in sale.picking_ids:
sum_qty_pick = sum(move_line.product_uom_qty for move_line in picking.move_ids_without_package)
sum_qty_reserved = sum(move_line.product_uom_qty for move_line in picking.move_line_ids_without_package)
if picking.state == 'done':
continue
- elif sum_qty_pick == sum_qty_reserved and not picking.date_reserved:# baru ke reserved
+ elif sum_qty_pick == sum_qty_reserved and not picking.date_reserved: # baru ke reserved
current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
picking.date_reserved = current_time
- elif sum_qty_pick == sum_qty_reserved:# sudah ada data reserved
+ elif sum_qty_pick == sum_qty_reserved: # sudah ada data reserved
picking.date_reserved = picking.date_reserved
else:
picking.date_reserved = ''
@@ -1054,7 +1086,7 @@ class SaleOrder(models.Model):
@api.onchange('partner_id')
def onchange_partner_contact(self):
parent_id = self.partner_id.parent_id
- parent_id = parent_id if parent_id else self.partner_id
+ parent_id = parent_id if parent_id else self.partner_id
self.npwp = parent_id.npwp
self.sppkp = parent_id.sppkp
@@ -1062,13 +1094,13 @@ class SaleOrder(models.Model):
self.email = parent_id.email
self.pareto_status = parent_id.pareto_status
self.user_id = parent_id.user_id
-
+
@api.onchange('partner_id')
def onchange_partner_id(self):
# INHERIT
result = super(SaleOrder, self).onchange_partner_id()
parent_id = self.partner_id.parent_id
- parent_id = parent_id if parent_id else self.partner_id
+ parent_id = parent_id if parent_id else self.partner_id
self.partner_invoice_id = parent_id
return result
@@ -1101,16 +1133,16 @@ class SaleOrder(models.Model):
minimum_amount = 20000000
for order in self:
order.have_visit_service = self.amount_total > minimum_amount
-
+
def _get_helper_ids(self):
helper_ids_str = self.env['ir.config_parameter'].sudo().get_param('sale.order.user_helper_ids')
return helper_ids_str.split(', ')
-
+
def write(self, values):
helper_ids = self._get_helper_ids()
if str(self.env.user.id) in helper_ids:
values['helper_by_id'] = self.env.user.id
-
+
return super(SaleOrder, self).write(values)
def check_due(self):
@@ -1128,21 +1160,21 @@ class SaleOrder(models.Model):
def _validate_order(self):
if self.payment_term_id.id == 31 and self.total_percent_margin < 25:
raise UserError("Jika ingin menggunakan Tempo 90 Hari maka margin harus di atas 25%")
-
- if self.warehouse_id.id != 8 and self.warehouse_id.id != 10: #GD Bandengan
+
+ if self.warehouse_id.id != 8 and self.warehouse_id.id != 10: # GD Bandengan
raise UserError('Gudang harus Bandengan')
-
+
if self.state not in ['draft', 'sent']:
raise UserError("Status harus draft atau sent")
-
+
self._validate_npwp()
-
+
def _validate_npwp(self):
num_digits = sum(c.isdigit() for c in self.npwp)
if num_digits < 10:
raise UserError("NPWP harus memiliki minimal 10 digit")
-
+
# pattern = r'^\d{10,}$'
# return re.match(pattern, self.npwp) is not None
@@ -1170,7 +1202,8 @@ class SaleOrder(models.Model):
if (partner.customer_type == 'pkp' or order.customer_type == 'pkp') and order.sppkp != partner.sppkp:
raise UserError("SPPKP berbeda pada Master Data Customer")
if not order.client_order_ref and order.create_date > datetime(2024, 6, 27):
- raise UserError("Customer Reference kosong, di isi dengan NO PO jika PO tidak ada mohon ditulis Tanpa PO")
+ raise UserError(
+ "Customer Reference kosong, di isi dengan NO PO jika PO tidak ada mohon ditulis Tanpa PO")
if not order.user_id.active:
raise UserError("Salesperson sudah tidak aktif, mohon diisi yang benar pada data SO dan Contact")
@@ -1178,20 +1211,23 @@ class SaleOrder(models.Model):
for order in self:
for line in order.order_line:
if 'bom-it' in line.name.lower() or 'bom' in line.product_id.default_code.lower() if line.product_id.default_code else False:
- search_bom = self.env['mrp.production'].search([('product_id', '=', line.product_id.id)],order='name desc')
+ search_bom = self.env['mrp.production'].search([('product_id', '=', line.product_id.id)],
+ order='name desc')
if search_bom:
confirmed_bom = search_bom.filtered(lambda x: x.state == 'confirmed')
if not confirmed_bom:
- raise UserError("Product BOM belum dikonfirmasi di Manufacturing Orders. Silakan hubungi MD.")
+ 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))
+ 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()
@@ -1214,11 +1250,13 @@ class SaleOrder(models.Model):
SYSTEM_UID = 25
FROM_WEBSITE = order.create_uid.id == SYSTEM_UID
- if FROM_WEBSITE and main_parent.use_so_approval and order.web_approval not in ['cust_procurement','cust_director']:
+ if FROM_WEBSITE and main_parent.use_so_approval and order.web_approval not in ['cust_procurement',
+ 'cust_director']:
raise UserError("This order not yet approved by customer procurement or director")
if not order.client_order_ref and order.create_date > datetime(2024, 6, 27):
- raise UserError("Customer Reference kosong, di isi dengan NO PO jika PO tidak ada mohon ditulis Tanpa PO")
+ raise UserError(
+ "Customer Reference kosong, di isi dengan NO PO jika PO tidak ada mohon ditulis Tanpa PO")
if not order.commitment_date and order.create_date > datetime(2024, 9, 12):
raise UserError("Expected Delivery Date kosong, wajib diisi")
@@ -1227,7 +1265,8 @@ class SaleOrder(models.Model):
UserError('Real Delivery Address harus di isi')
if order.validate_partner_invoice_due():
- return self._create_notification_action('Notification','Terdapat invoice yang telah melewati batas waktu, mohon perbarui pada dokumen Due Extension')
+ return self._create_notification_action('Notification',
+ 'Terdapat invoice yang telah melewati batas waktu, mohon perbarui pada dokumen Due Extension')
term_days = 0
for term_line in order.payment_term_id.line_ids:
@@ -1245,13 +1284,15 @@ class SaleOrder(models.Model):
if (partner.customer_type == 'pkp' or order.customer_type == 'pkp') and order.sppkp != partner.sppkp:
raise UserError("SPPKP berbeda pada Master Data Customer")
if not order.client_order_ref and order.create_date > datetime(2024, 6, 27):
- raise UserError("Customer Reference kosong, di isi dengan NO PO jika PO tidak ada mohon ditulis Tanpa PO")
+ raise UserError(
+ "Customer Reference kosong, di isi dengan NO PO jika PO tidak ada mohon ditulis Tanpa PO")
if not order.user_id.active:
raise UserError("Salesperson sudah tidak aktif, mohon diisi yang benar pada data SO dan Contact")
-
+
if order.validate_partner_invoice_due():
- return self._create_notification_action('Notification', 'Terdapat invoice yang telah melewati batas waktu, mohon perbarui pada dokumen Due Extension')
-
+ return self._create_notification_action('Notification',
+ 'Terdapat invoice yang telah melewati batas waktu, mohon perbarui pada dokumen Due Extension')
+
if order._requires_approval_margin_leader():
order.approval_status = 'pengajuan2'
return self._create_approval_notification('Pimpinan')
@@ -1261,9 +1302,9 @@ class SaleOrder(models.Model):
self.check_limit_so_to_invoice()
order.approval_status = 'pengajuan1'
return self._create_approval_notification('Sales Manager')
-
+
raise UserError("Bisa langsung Confirm")
-
+
def send_notif_to_salesperson(self, cancel=False):
if not cancel:
@@ -1281,7 +1322,9 @@ class SaleOrder(models.Model):
salesperson_data = {}
for rec in grouping_so:
if rec.user_id.id not in salesperson_data:
- salesperson_data[rec.user_id.id] = {'name': rec.user_id.name, 'orders': [], 'total_amount': 0, 'sum_total_amount': 0, 'business_partner': '', 'site': ''} # Menetapkan nilai awal untuk 'site'
+ salesperson_data[rec.user_id.id] = {'name': rec.user_id.name, 'orders': [], 'total_amount': 0,
+ 'sum_total_amount': 0, 'business_partner': '',
+ 'site': ''} # Menetapkan nilai awal untuk 'site'
if rec.picking_ids:
if not any(picking.state in ['assigned', 'confirmed', 'waiting'] for picking in rec.picking_ids):
continue
@@ -1300,7 +1343,8 @@ class SaleOrder(models.Model):
})
salesperson_data[rec.user_id.id]['sum_total_amount'] += order_total_amount
salesperson_data[rec.user_id.id]['business_partner'] = grouping_so[0].partner_id.main_parent_id.name
- salesperson_data[rec.user_id.id]['site'] = grouping_so[0].partner_id.site_id.name # Menambahkan nilai hanya jika ada
+ salesperson_data[rec.user_id.id]['site'] = grouping_so[
+ 0].partner_id.site_id.name # Menambahkan nilai hanya jika ada
# Kirim email untuk setiap salesperson
for salesperson_id, data in salesperson_data.items():
@@ -1324,9 +1368,9 @@ class SaleOrder(models.Model):
template = self.env.ref('indoteknik_custom.mail_template_sale_order_notification_to_salesperson')
email_body = template.body_html.replace('${table_content}', table_content)
email_body = email_body.replace('${salesperson_name}', data['name'])
- email_body = email_body.replace('${sum_total_amount}', str(data['sum_total_amount']))
- email_body = email_body.replace('${site}', str(data['site']))
- email_body = email_body.replace('${business_partner}', str(data['business_partner']))
+ email_body = email_body.replace('${sum_total_amount}', str(data['sum_total_amount']))
+ email_body = email_body.replace('${site}', str(data['site']))
+ email_body = email_body.replace('${business_partner}', str(data['business_partner']))
# Kirim email
self.env['mail.mail'].create({
'subject': 'Notification: Sale Orders',
@@ -1362,8 +1406,9 @@ class SaleOrder(models.Model):
if (outstanding_amount + rec.amount_total) >= block_stage:
if block_stage != 0:
remaining_credit_limit = block_stage - outstanding_amount
- raise UserError(_("%s is in Blocking Stage, Remaining credit limit is %s, from %s and outstanding %s")
- % (rec.partner_id.name, remaining_credit_limit, block_stage, outstanding_amount))
+ raise UserError(
+ _("%s is in Blocking Stage, Remaining credit limit is %s, from %s and outstanding %s")
+ % (rec.partner_id.name, remaining_credit_limit, block_stage, outstanding_amount))
def check_limit_so_to_invoice(self):
for rec in self:
@@ -1385,7 +1430,8 @@ class SaleOrder(models.Model):
# Validasi limit
if remaining_credit_limit <= 0 and block_stage > 0 and not is_cbd:
- raise UserError(_("The credit limit for %s will exceed the Blocking Stage if the Sale Order is confirmed. The remaining credit limit is %s, from %s and the outstanding amount is %s.")
+ raise UserError(
+ _("The credit limit for %s will exceed the Blocking Stage if the Sale Order is confirmed. The remaining credit limit is %s, from %s and the outstanding amount is %s.")
% (rec.partner_id.name, block_stage - current_total, block_stage, outstanding_amount))
def validate_different_vendor(self):
@@ -1395,11 +1441,11 @@ class SaleOrder(models.Model):
if self.vendor_approval_id and all(v.state != 'draft' for v in self.vendor_approval_id):
return False
-
+
different_vendor = self.order_line.filtered(
lambda l: l.vendor_id and l.vendor_md_id and l.vendor_id.id != l.vendor_md_id.id
)
-
+
if different_vendor:
vendor_approvals = []
for line in different_vendor:
@@ -1425,15 +1471,14 @@ class SaleOrder(models.Model):
if line.purchase_price_md else False
),
})
-
+
vendor_approvals.append(vendor_approval.id)
-
+
self.vendor_approval_id = [(4, vid) for vid in vendor_approvals]
return True
else:
return False
-
def action_confirm(self):
for order in self:
order._validate_uniform_taxes()
@@ -1443,38 +1488,41 @@ class SaleOrder(models.Model):
order.check_limit_so_to_invoice()
if self.validate_different_vendor() and not self.vendor_approval:
return self._create_notification_action('Notification', 'Terdapat Vendor yang berbeda dengan MD Vendor')
-
+
order.check_data_real_delivery_address()
order.sale_order_check_approve()
order._validate_order()
order.order_line.validate_line()
-
+
main_parent = order.partner_id.get_main_parent()
SYSTEM_UID = 25
FROM_WEBSITE = order.create_uid.id == SYSTEM_UID
-
- if FROM_WEBSITE and main_parent.use_so_approval and order.web_approval not in ['cust_procurement', 'cust_director']:
+
+ if FROM_WEBSITE and main_parent.use_so_approval and order.web_approval not in ['cust_procurement',
+ 'cust_director']:
raise UserError("This order not yet approved by customer procurement or director")
if not order.client_order_ref and order.create_date > datetime(2024, 6, 27):
- raise UserError("Customer Reference kosong, di isi dengan NO PO jika PO tidak ada mohon ditulis Tanpa PO")
+ raise UserError(
+ "Customer Reference kosong, di isi dengan NO PO jika PO tidak ada mohon ditulis Tanpa PO")
if not order.commitment_date and order.create_date > datetime(2024, 9, 12):
raise UserError("Expected Delivery Date kosong, wajib diisi")
-
+
if not order.real_shipping_id:
UserError('Real Delivery Address harus di isi')
-
+
if order.validate_partner_invoice_due():
- return self._create_notification_action('Notification', 'Terdapat invoice yang telah melewati batas waktu, mohon perbarui pada dokumen Due Extension')
-
+ return self._create_notification_action('Notification',
+ 'Terdapat invoice yang telah melewati batas waktu, mohon perbarui pada dokumen Due Extension')
+
if order._requires_approval_margin_leader():
order.approval_status = 'pengajuan2'
return self._create_approval_notification('Pimpinan')
elif order._requires_approval_margin_manager():
order.approval_status = 'pengajuan1'
return self._create_approval_notification('Sales Manager')
-
+
order.approval_status = 'approved'
order._set_sppkp_npwp_contact()
order.calculate_line_no()
@@ -1488,7 +1536,7 @@ class SaleOrder(models.Model):
for line in order.order_line:
if line.display_type == 'line_note':
note.append(line.name)
-
+
if order.picking_ids:
# Sort picking_ids by creation date to get the most recent one
latest_picking = order.picking_ids.sorted(key=lambda p: p.create_date, reverse=True)[0]
@@ -1502,7 +1550,7 @@ class SaleOrder(models.Model):
main_parent = self.partner_id.get_main_parent()
if self._name != 'sale.order':
return super(SaleOrder, self).action_cancel()
-
+
if self.have_outstanding_invoice:
raise UserError("Invoice harus di Cancel dahulu")
@@ -1513,7 +1561,7 @@ class SaleOrder(models.Model):
for line in self.order_line:
if line.qty_delivered > 0:
raise UserError("DO yang done harus di-Return oleh Logistik")
-
+
if not self.web_approval:
self.web_approval = 'company'
# elif self.have_outstanding_po:
@@ -1543,11 +1591,11 @@ class SaleOrder(models.Model):
def validate_partner_invoice_due(self):
parent_id = self.partner_id.parent_id.id
- parent_id = parent_id if parent_id else self.partner_id.id
+ parent_id = parent_id if parent_id else self.partner_id.id
if self.due_id and self.due_id.is_approve == False:
raise UserError('Document Over Due Yang Anda Buat Belum Di Approve')
-
+
query = [
('partner_id', '=', parent_id),
('state', '=', 'posted'),
@@ -1570,27 +1618,27 @@ class SaleOrder(models.Model):
else:
due_extension.unlink()
return False
-
+
def _requires_approval_margin_leader(self):
return self.total_percent_margin <= 15 and not self.env.user.is_leader
-
+
def _requires_approval_margin_manager(self):
return 15 < self.total_percent_margin <= 24 and not self.env.user.is_sales_manager and not self.env.user.is_leader
# return self.total_percent_margin >= 15 and not self.env.user.is_leader and not self.env.user.is_sales_manager
-
+
def _create_approval_notification(self, approval_role):
title = 'Warning'
message = f'SO butuh approval {approval_role}'
return self._create_notification_action(title, message)
-
+
def _create_notification_action(self, title, message):
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
- 'params': { 'title': title, 'message': message, 'next': {'type': 'ir.actions.act_window_close'} },
+ 'params': {'title': title, 'message': message, 'next': {'type': 'ir.actions.act_window_close'}},
}
-
- def _set_sppkp_npwp_contact(self):
+
+ def _set_sppkp_npwp_contact(self):
partner = self.partner_id.parent_id or self.partner_id
if not partner.sppkp:
@@ -1609,7 +1657,7 @@ class SaleOrder(models.Model):
# partner.npwp = self.npwp
# partner.sppkp = self.sppkp
# partner.email = self.email
-
+
def _compute_total_margin(self):
for order in self:
total_margin = sum(line.item_margin for line in order.order_line if line.product_id)
@@ -1617,7 +1665,7 @@ class SaleOrder(models.Model):
total_margin -= order.ongkir_ke_xpdc
order.total_margin = total_margin
-
+
def _compute_total_before_margin(self):
for order in self:
total_before_margin = sum(line.item_before_margin for line in order.order_line if line.product_id)
@@ -1632,9 +1680,10 @@ class SaleOrder(models.Model):
delivery_amt = order.delivery_amt
else:
delivery_amt = 0
-
+
# order.total_percent_margin = round((order.total_margin / (order.amount_untaxed-delivery_amt-order.fee_third_party)) * 100, 2)
- order.total_percent_margin = round((order.total_margin / (order.amount_untaxed-order.fee_third_party-order.biaya_lain_lain)) * 100, 2)
+ order.total_percent_margin = round(
+ (order.total_margin / (order.amount_untaxed - order.fee_third_party - order.biaya_lain_lain)) * 100, 2)
# order.total_percent_margin = round((order.total_margin / (order.amount_untaxed)) * 100, 2)
@api.onchange('sales_tax_id')
@@ -1657,20 +1706,20 @@ class SaleOrder(models.Model):
voucher = self.voucher_id
if voucher.limit > 0 and voucher.count_order >= voucher.limit:
raise UserError('Voucher tidak dapat digunakan karena sudah habis digunakan')
-
+
partner_voucher_orders = []
for order in voucher.order_ids:
if order.partner_id.id == self.partner_id.id:
partner_voucher_orders.append(order)
-
+
if voucher.limit_user > 0 and len(partner_voucher_orders) >= voucher.limit_user:
raise UserError('Voucher tidak dapat digunakan karena Customer ini sudah menghabiskan kuota voucher')
-
+
if self.pricelist_id.id in [x.id for x in voucher.excl_pricelist_ids]:
raise UserError('Voucher tidak dapat digunakan karena pricelist ini tidak berlaku pada voucher')
-
+
self.apply_voucher()
-
+
def action_apply_voucher_shipping(self):
for line in self.order_line:
if line.order_promotion_id:
@@ -1679,18 +1728,18 @@ class SaleOrder(models.Model):
voucher = self.voucher_shipping_id
if voucher.limit > 0 and voucher.count_order >= voucher.limit:
raise UserError('Voucher tidak dapat digunakan karena sudah habis digunakan')
-
+
partner_voucher_orders = []
for order in voucher.order_ids:
if order.partner_id.id == self.partner_id.id:
partner_voucher_orders.append(order)
-
+
if voucher.limit_user > 0 and len(partner_voucher_orders) >= voucher.limit_user:
raise UserError('Voucher tidak dapat digunakan karena Customer ini sudah menghabiskan kuota voucher')
-
+
if self.pricelist_id.id in [x.id for x in voucher.excl_pricelist_ids]:
raise UserError('Voucher tidak dapat digunakan karena pricelist ini tidak berlaku pada voucher')
-
+
self.apply_voucher_shipping()
def apply_voucher(self):
@@ -1707,7 +1756,7 @@ class SaleOrder(models.Model):
for line in self.order_line:
line.initial_discount = line.discount
-
+
voucher_type = voucher['type']
used_total = voucher['total'][voucher_type]
used_discount = voucher['discount'][voucher_type]
@@ -1723,11 +1772,11 @@ class SaleOrder(models.Model):
line_contribution = line.price_subtotal / used_total
line_voucher = used_discount * line_contribution
line_voucher_item = line_voucher / line.product_uom_qty
-
+
line_price_unit = line.price_unit / 1.11 if any(tax.id == 23 for tax in line.tax_id) else line.price_unit
line_discount_item = line_price_unit * line.discount / 100 + line_voucher_item
line_voucher_item = line_discount_item / line_price_unit * 100
-
+
line.amount_voucher_disc = line_voucher
line.discount = line_voucher_item
@@ -1738,27 +1787,27 @@ class SaleOrder(models.Model):
for order in self:
delivery_amt = order.delivery_amt
voucher = order.voucher_shipping_id
-
+
if voucher:
max_discount_amount = voucher.discount_amount
voucher_type = voucher.discount_type
-
+
if voucher_type == 'fixed_price':
discount = max_discount_amount
elif voucher_type == 'percentage':
discount = delivery_amt * (max_discount_amount / 100)
-
+
delivery_amt -= discount
-
+
delivery_amt = max(delivery_amt, 0)
-
+
order.delivery_amt = delivery_amt
-
+
order.amount_voucher_shipping_disc = discount
order.applied_voucher_shipping_id = order.voucher_id.id
def cancel_voucher(self):
- self.applied_voucher_id = False
+ self.applied_voucher_id = False
self.amount_voucher_disc = 0
for line in self.order_line:
line.amount_voucher_disc = 0
@@ -1767,17 +1816,18 @@ class SaleOrder(models.Model):
def cancel_voucher_shipping(self):
self.delivery_amt + self.amount_voucher_shipping_disc
- self.applied_voucher_shipping_id = False
+ self.applied_voucher_shipping_id = False
self.amount_voucher_shipping_disc = 0
def action_web_approve(self):
if self.env.uid != self.partner_id.user_id.id:
- raise UserError('You are not authorized to approve this order. Only %s can approve this order.' % self.partner_id.user_id.name)
-
+ raise UserError(
+ 'You are not authorized to approve this order. Only %s can approve this order.' % self.partner_id.user_id.name)
+
self.web_approval = 'company'
template = self.env.ref('indoteknik_custom.mail_template_sale_order_web_approve_notification')
template.send_mail(self.id, force_send=True)
-
+
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
@@ -1837,13 +1887,14 @@ class SaleOrder(models.Model):
if last_so and rec_purchase_price != last_so.purchase_price:
rec_taxes = self.env['account.tax'].search([('id', '=', rec_taxes_id)], limit=1)
if rec_taxes.price_include:
- selling_price = (rec_purchase_price / 1.11) / (1 - (last_so.item_percent_margin_without_deduction / 100))
+ selling_price = (rec_purchase_price / 1.11) / (
+ 1 - (last_so.item_percent_margin_without_deduction / 100))
else:
selling_price = rec_purchase_price / (1 - (last_so.item_percent_margin_without_deduction / 100))
tax_id = last_so.tax_id
for tax in tax_id:
if tax.price_include:
- selling_price = selling_price + (selling_price*11/100)
+ selling_price = selling_price + (selling_price * 11 / 100)
else:
selling_price = selling_price
discount = 0
@@ -1859,13 +1910,14 @@ class SaleOrder(models.Model):
elif last_so and rec_vendor_id == order_line.vendor_id.id and rec_purchase_price != last_so.purchase_price:
rec_taxes = self.env['account.tax'].search([('id', '=', rec_taxes_id)], limit=1)
if rec_taxes.price_include:
- selling_price = (rec_purchase_price / 1.11) / (1 - (last_so.item_percent_margin_without_deduction / 100))
+ selling_price = (rec_purchase_price / 1.11) / (
+ 1 - (last_so.item_percent_margin_without_deduction / 100))
else:
selling_price = rec_purchase_price / (1 - (last_so.item_percent_margin_without_deduction / 100))
tax_id = last_so.tax_id
for tax in tax_id:
if tax.price_include:
- selling_price = selling_price + (selling_price*11/100)
+ selling_price = selling_price + (selling_price * 11 / 100)
else:
selling_price = selling_price
discount = 0
@@ -1896,14 +1948,14 @@ class SaleOrder(models.Model):
return order
# def write(self, vals):
- # Call the super method to handle the write operation
- # res = super(SaleOrder, self).write(vals)
- # self._compute_etrts_date()
- # Check if the update is coming from a save operation
- # if any(field in vals for field in ['sppkp', 'npwp', 'email', 'customer_type']):
- # self._update_partner_details()
+ # Call the super method to handle the write operation
+ # res = super(SaleOrder, self).write(vals)
+ # self._compute_etrts_date()
+ # Check if the update is coming from a save operation
+ # if any(field in vals for field in ['sppkp', 'npwp', 'email', 'customer_type']):
+ # self._update_partner_details()
- # return res
+ # return res
def _update_partner_details(self):
for order in self:
@@ -1932,11 +1984,11 @@ class SaleOrder(models.Model):
if command[0] == 0: # A new line is being added
raise UserError(
"SO tidak dapat ditambahkan produk baru karena SO sudah menjadi sale order.")
-
+
res = super(SaleOrder, self).write(vals)
# self._check_total_margin_excl_third_party()
if any(fields in vals for fields in ['delivery_amt', 'carrier_id', 'shipping_cost_covered']):
self._validate_delivery_amt()
if any(field in vals for field in ["order_line", "client_order_ref"]):
- self._calculate_etrts_date()
- return res \ No newline at end of file
+ self._calculate_etrts_date()
+ return res
diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml
index e0085eeb..10682e93 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -4,222 +4,225 @@
<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="hold_unhold_qty_outgoing_so"
- string="Hold/Unhold Outgoing"
- type="object"
- attrs="{'invisible': [('state', 'in', ['cancel'])]}"
+ string="Hold/Unhold Outgoing"
+ type="object"
+ attrs="{'invisible': [('state', 'in', ['cancel'])]}"
/>
<button name="ask_retur_cancel_purchasing"
- string="Ask Cancel Purchasing"
- type="object"
- attrs="{'invisible': [('state', 'in', ['cancel'])]}"
+ string="Ask Cancel Purchasing"
+ type="object"
+ attrs="{'invisible': [('state', 'in', ['cancel'])]}"
/>
<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')]}" />
+ 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="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)]}" />
+ 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" />
+ 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="applied_voucher_id" invisible="1" />
+ 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"
- attrs="{'invisible': ['|', '|', ('voucher_id', '=', False), ('state', 'not in', ['draft', 'sent']), ('applied_voucher_id', '!=', False)]}"
+ 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"
- attrs="{'invisible': ['|', ('applied_voucher_id', '=', False), ('state', 'not in', ['draft','sent'])]}"
+ 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="applied_voucher_shipping_id" invisible="1" />
+ 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"
- attrs="{'invisible': ['|', '|', ('voucher_id', '=', False), ('state', 'not in', ['draft', 'sent']), ('applied_voucher_shipping_id', '!=', False)]}"
+ 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"
- attrs="{'invisible': ['|', ('applied_voucher_shipping_id', '=', False), ('state', 'not in', ['draft','sent'])]}"
+ 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="approval_status" position="after">
+ <field name="notes"/>
+ </field>
<field name="source_id" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="user_id" position="after">
- <field name="hold_outgoing" readonly="1" />
- <field name="helper_by_id" readonly="1" />
- <field name="compute_fullfillment" invisible="1" />
+ <field name="hold_outgoing" readonly="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="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="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>
<field name="analytic_account_id" position="after">
- <field name="customer_type" readonly="1" />
- <field name="npwp" placeholder='99.999.999.9-999.999' readonly="1" />
- <field name="sppkp" attrs="{'required': [('customer_type', '=', 'pkp')]}" readonly="1" />
- <field name="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" readonly="1"/>
+ <field name="npwp" placeholder='99.999.999.9-999.999' readonly="1"/>
+ <field name="sppkp" attrs="{'required': [('customer_type', '=', 'pkp')]}" readonly="1"/>
+ <field name="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="approval_status" />
+ <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" />
+ 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">
+ position="attributes">
<attribute name="attrs">
- {'readonly': [('state', 'in', ('done','cancel'))]}
+ {'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" />
+ 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">
+ 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">
+ 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" />
+ 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" />
+ 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" />
+ 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" />
+ 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" />
+ 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" />
+ 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" />
+ 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" />
+ 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="
+ attrs="
{
'readonly': [
'|',
@@ -227,35 +230,35 @@
('parent.approval_status', '!=', False)
]
}
- " />
- <field name="purchase_price_md" 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" />
+ 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" />
+ 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" />
+ 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">
+ 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
@@ -264,42 +267,42 @@
<attribute name="required">1</attribute>
</xpath> -->
<field name="amount_total" position="after">
- <field name="grand_total" />
- <label for="amount_voucher_disc" string="Voucher" />
+ <field name="grand_total"/>
+ <label for="amount_voucher_disc" string="Voucher"/>
<div>
- <field class="mb-0" name="amount_voucher_disc" string="Voucher" readonly="1" />
+ <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" />
+ <label for="amount_voucher_shipping_disc" string="Voucher Shipping"/>
<div>
<field class="mb-0" name="amount_voucher_shipping_disc"
- string="Voucher Shipping" readonly="1" />
+ 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_before_margin" />
+ <field name="total_margin"/>
+ <field name="total_percent_margin"/>
+ <field name="total_before_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'])]}
+ ['cancel', 'draft'])]}
</attribute>
</field>
<field name="payment_term_id" position="attributes">
<attribute name="attrs">
{'readonly': [('approval_status', '=', 'approved'), ('state', 'not in',
- ['cancel','draft'])]}
+ ['cancel', 'draft'])]}
</attribute>
</field>
@@ -307,55 +310,55 @@
<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>
<page string="Promotion" name="page_promotion">
<field name="order_promotion_ids" readonly="1">
<tree options="{'no_open': True}">
- <field name="program_line_id" />
- <field name="quantity" />
- <field name="is_applied" />
+ <field name="program_line_id"/>
+ <field name="quantity"/>
+ <field name="is_applied"/>
</tree>
<form>
<group>
- <field name="program_line_id" />
- <field name="quantity" />
- <field name="is_applied" />
+ <field name="program_line_id"/>
+ <field name="quantity"/>
+ <field name="is_applied"/>
</group>
</form>
</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="0" />
+ <field name="reject_line" readonly="0"/>
</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>
@@ -367,15 +370,15 @@
<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="reason_cancel" widget="selection"/>
+ <field name="attachment_bukti" widget="many2many_binary" required="1"/>
<field name="nomor_so_pengganti"
- attrs="{'invisible': [('reason_cancel', '!=', 'ganti_quotation')]}" />
+ 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" />
+ class="btn-primary"/>
+ <button string="Cancel" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
@@ -392,43 +395,44 @@
<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="hold_outgoing" optional="hide" />
+ <field name="approval_status"/>
+ <field name="client_order_ref"/>
+ <field name="notes"/>
+ <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="hold_outgoing" 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="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>
</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>
@@ -436,32 +440,32 @@
<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;">
+ 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;">
+ 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;">
+ width="590"
+ style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
<tr>
<td style="padding-bottom: 24px;">
Dear
@@ -478,8 +482,8 @@
<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;">
+ 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>
@@ -522,11 +526,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>
@@ -538,9 +542,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>
@@ -554,14 +558,14 @@
<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" />
+ <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>
@@ -571,10 +575,10 @@
<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>
@@ -586,9 +590,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="0" />
+ <field name="product_id" readonly="1"/>
+ <field name="qty_reject" readonly="1"/>
+ <field name="reason_reject" readonly="0"/>
</tree>
</field>
</record>
@@ -597,8 +601,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>
@@ -607,24 +611,24 @@
<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;">
+ 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;">
+ 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;">
+ width="590"
+ style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
<tr>
<td valign="middle">
<span></span>
@@ -637,8 +641,8 @@
<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;">
+ 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>
@@ -655,7 +659,7 @@
<tr>
<td>
<table border="1" cellpadding="5"
- cellspacing="0">
+ cellspacing="0">
<thead>
<tr>
<th>Nama Pesanan</th>
@@ -674,7 +678,7 @@
<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;" />
+ 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>