summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFIN-IT_AndriFP <it@fixcomart.co.id>2025-10-23 09:50:40 +0700
committerFIN-IT_AndriFP <it@fixcomart.co.id>2025-10-23 09:50:40 +0700
commit310f92c9b825a458618daa3b00581b790f8e009e (patch)
tree2b8957db596c86525c009ef5e62e23ccd6397f8f
parent58a6ca75b9b1bb07ea958ab4bfb553140daeb8f8 (diff)
parent8d649f97dade329859b5770d1f3972cdd7233f97 (diff)
Merge branch 'odoo-backup' of https://bitbucket.org/altafixco/indoteknik-addons into pum-v3
-rw-r--r--indoteknik_api/controllers/api_v1/sale_order.py14
-rw-r--r--indoteknik_api/controllers/api_v1/stock_picking.py12
-rw-r--r--indoteknik_custom/models/account_asset.py4
-rw-r--r--indoteknik_custom/models/commision.py8
-rw-r--r--indoteknik_custom/models/mrp_production.py3
-rw-r--r--indoteknik_custom/models/partial_delivery.py52
-rwxr-xr-xindoteknik_custom/models/purchase_order.py68
-rwxr-xr-xindoteknik_custom/models/purchase_order_line.py6
-rw-r--r--indoteknik_custom/models/purchase_order_sales_match.py5
-rwxr-xr-xindoteknik_custom/models/sale_order.py10
-rw-r--r--indoteknik_custom/models/sale_order_line.py62
-rw-r--r--indoteknik_custom/models/sj_tele.py10
-rw-r--r--indoteknik_custom/models/stock_move.py17
-rw-r--r--indoteknik_custom/models/stock_picking.py19
-rw-r--r--indoteknik_custom/views/account_asset_views.xml3
-rwxr-xr-xindoteknik_custom/views/purchase_order.xml2
16 files changed, 182 insertions, 113 deletions
diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py
index 56b49f9a..cff1921d 100644
--- a/indoteknik_api/controllers/api_v1/sale_order.py
+++ b/indoteknik_api/controllers/api_v1/sale_order.py
@@ -231,10 +231,11 @@ class SaleOrder(controller.Controller):
for so in filtered_orders_paginated:
item = request.env['sale.order'].api_v1_single_response(so)
+ approval_ok = (so.approval_status in ('pengajuan1', 'pengajuan2'))
source_ok = _is_website_order(so)
term_ok = bool(so.payment_term_id and so.payment_term_id.id == CBD_PAYMENT_TERM_ID)
pay_status = (getattr(so, 'payment_status', '') or '').strip().lower()
- eligible = bool(source_ok and term_ok and pay_status in ALLOWED_CONTINUE)
+ eligible = bool(approval_ok and source_ok and term_ok and pay_status in ALLOWED_CONTINUE)
redirect_url = getattr(so, 'payment_link_midtrans', '') or ''
@@ -242,6 +243,7 @@ class SaleOrder(controller.Controller):
'eligibleContinue': eligible,
'paymentSummary': {
'eligible': eligible,
+ 'approvalStatus': so.approval_status or '',
'paymentStatus': pay_status,
'paymentTermId': so.payment_term_id.id if so.payment_term_id else None,
'sourceId': so.source_id.id if so.source_id else None,
@@ -283,6 +285,7 @@ class SaleOrder(controller.Controller):
pay_status = (getattr(sale_order, 'payment_status', '') or '').strip().lower()
eligible = (
+ sale_order.approval_status in ('pengajuan1', 'pengajuan2') and
_is_website_order(sale_order) and
sale_order.payment_term_id and sale_order.payment_term_id.id == CBD_PAYMENT_TERM_ID and
pay_status in ALLOWED_CONTINUE
@@ -314,6 +317,7 @@ class SaleOrder(controller.Controller):
'eligible_continue': eligible,
'payment_summary': {
'eligible': eligible,
+ 'approval_status': sale_order.approval_status or '',
'payment_status': pay_status,
'payment_term_id': sale_order.payment_term_id.id if sale_order.payment_term_id else None,
'source_id': sale_order.source_id.id if sale_order.source_id else None,
@@ -723,9 +727,9 @@ class SaleOrder(controller.Controller):
_logger.info(f"Updated user_id from partner: {parameters['user_id']}")
if params['value']['type'] == 'sale_order':
- # parameters['approval_status'] = 'pengajuan1'
- parameters['approval_status'] = False
- _logger.info("Setting approval_status to 'false'")
+ parameters['approval_status'] = 'pengajuan1'
+ # parameters['approval_status'] = False
+ _logger.info("Setting approval_status to 'pengajuan1'")
sale_order = request.env['sale.order'].with_context(from_website_checkout=True).create([parameters])
sale_order.onchange_partner_contact()
@@ -785,7 +789,7 @@ class SaleOrder(controller.Controller):
order_line.product_id_change()
order_line.weight = order_line.product_id.weight
- order_line.onchange_vendor_id()
+ order_line._onchange_vendor_id_custom()
_logger.info(f"After onchanges - Price: {order_line.price_unit}, Disc: {order_line.discount}")
elif cart['cart_type'] == 'promotion':
diff --git a/indoteknik_api/controllers/api_v1/stock_picking.py b/indoteknik_api/controllers/api_v1/stock_picking.py
index 2ec1ec2a..fe82e665 100644
--- a/indoteknik_api/controllers/api_v1/stock_picking.py
+++ b/indoteknik_api/controllers/api_v1/stock_picking.py
@@ -1,5 +1,5 @@
from .. import controller
-from odoo import http
+from odoo import http, fields
from odoo.http import request, Response
from pytz import timezone
from datetime import datetime
@@ -8,7 +8,6 @@ import logging
_logger = logging.getLogger(__name__)
-_logger = logging.getLogger(__name__)
class StockPicking(controller.Controller):
prefix = '/api/v1/'
@@ -128,6 +127,7 @@ class StockPicking(controller.Controller):
sj_document = kw.get('sj_document') if 'sj_document' in kw else None
paket_document = kw.get('paket_document') if 'paket_document' in kw else None
dispatch_document = kw.get('dispatch_document') if 'dispatch_document' in kw else None
+ self_pu= kw.get('self_pu') if 'self_pu' in kw else None
# ===== Cari picking by id / picking_code =====
picking_data = False
@@ -140,19 +140,21 @@ class StockPicking(controller.Controller):
if not picking_data:
return self.response(code=403, description='picking not found')
- params = {
- 'driver_arrival_date': datetime.utcnow(),
- }
+ params = {}
if sj_document:
params['sj_documentation'] = sj_document
+ if self_pu:
+ params['driver_arrival_date'] = datetime.utcnow()
if paket_document:
params['paket_documentation'] = paket_document
+ params['driver_arrival_date'] = datetime.utcnow()
if dispatch_document:
params['dispatch_documentation'] = dispatch_document
picking_data.write(params)
return self.response({'name': picking_data.name})
+
@http.route(prefix + 'webhook/biteship', type='json', auth='public', methods=['POST'], csrf=False)
def update_status_from_biteship(self, **kw):
_logger.info("Biteship Webhook: Request received at controller start (type='json').")
diff --git a/indoteknik_custom/models/account_asset.py b/indoteknik_custom/models/account_asset.py
index bd5f9adb..211ab229 100644
--- a/indoteknik_custom/models/account_asset.py
+++ b/indoteknik_custom/models/account_asset.py
@@ -4,6 +4,10 @@ from odoo.exceptions import AccessError, UserError, ValidationError
class AccountAsset(models.Model):
_inherit = 'account.asset.asset'
+ asset_type = fields.Selection(string='Tipe Aset', selection=[
+ ('aset_gudang', ' Aset Gudang'),
+ ('aset_kantor', 'Aset Kantor'),
+ ], tracking=True )
def action_close_asset(self):
for asset in self:
diff --git a/indoteknik_custom/models/commision.py b/indoteknik_custom/models/commision.py
index 6d538b83..a937e2d0 100644
--- a/indoteknik_custom/models/commision.py
+++ b/indoteknik_custom/models/commision.py
@@ -428,22 +428,22 @@ class CustomerCommision(models.Model):
if not self.status or self.status == 'draft':
self.status = 'pengajuan1'
- elif self.status == 'pengajuan1' and self.env.user.id == 19:
+ elif self.status == 'pengajuan1' and (self.env.user.id == 19 or self.env.user.has_group('indoteknik_custom.group_role_it')):
self.status = 'pengajuan2'
self.approved_by = (self.approved_by + ', ' if self.approved_by else '') + self.env.user.name
self.date_approved_sales = now_naive
self.position_sales = 'Sales Manager'
- elif self.status == 'pengajuan2' and self.env.user.id == 216:
+ elif self.status == 'pengajuan2' and (self.env.user.id == 216 or self.env.user.has_group('indoteknik_custom.group_role_it')):
self.status = 'pengajuan3'
self.approved_by = (self.approved_by + ', ' if self.approved_by else '') + self.env.user.name
self.date_approved_marketing = now_naive
self.position_marketing = 'Marketing Manager'
- elif self.status == 'pengajuan3' and self.env.user.is_leader:
+ elif self.status == 'pengajuan3' and (self.env.user.is_leader or self.env.user.has_group('indoteknik_custom.group_role_it')):
self.status = 'pengajuan4'
self.approved_by = (self.approved_by + ', ' if self.approved_by else '') + self.env.user.name
self.date_approved_pimpinan = now_naive
self.position_pimpinan = 'Pimpinan'
- elif self.status == 'pengajuan4' and self.env.user.id == 1272:
+ elif self.status == 'pengajuan4' and (self.env.user.id == 1272 or self.env.user.has_group('indoteknik_custom.group_role_it')):
for line in self.commision_lines:
line.invoice_id.is_customer_commision = True
if self.commision_type == 'fee':
diff --git a/indoteknik_custom/models/mrp_production.py b/indoteknik_custom/models/mrp_production.py
index 30956082..02679458 100644
--- a/indoteknik_custom/models/mrp_production.py
+++ b/indoteknik_custom/models/mrp_production.py
@@ -308,6 +308,9 @@ class CheckBomProduct(models.Model):
if not self.code_product:
return
+ if self.production_id.qty_producing == 0:
+ raise UserError("Isi dan Save dahulu Quantity To Produce yang diinginkan!")
+
# Cari product berdasarkan default_code, barcode, atau barcode_box
product = self.env['product.product'].search([
'|',
diff --git a/indoteknik_custom/models/partial_delivery.py b/indoteknik_custom/models/partial_delivery.py
index 83fe9981..4df7da1e 100644
--- a/indoteknik_custom/models/partial_delivery.py
+++ b/indoteknik_custom/models/partial_delivery.py
@@ -46,7 +46,6 @@ class PartialDeliveryWizard(models.TransientModel):
raise UserError(_("Tidak ada produk yang dipilih."))
for line in self.line_ids:
line.selected = True
- # return action supaya wizard gak nutup
return {
'type': 'ir.actions.act_window',
'res_model': self._name,
@@ -60,7 +59,6 @@ class PartialDeliveryWizard(models.TransientModel):
raise UserError(_("Tidak ada produk yang dipilih."))
for line in self.line_ids:
line.selected = False
- # juga reload biar tetap di wizard
return {
'type': 'ir.actions.act_window',
'res_model': self._name,
@@ -76,7 +74,6 @@ class PartialDeliveryWizard(models.TransientModel):
self.line_ids = [(5, 0, 0)]
return
- # ๐Ÿงน hapus line lama dulu
if self.line_ids:
self.line_ids.unlink()
@@ -95,7 +92,7 @@ class PartialDeliveryWizard(models.TransientModel):
'wizard_id': self.id,
'product_id': move.product_id.id,
'reserved_qty': reserved_qty,
- 'selected_qty': reserved_qty, # biar langsung keisi default
+ # 'selected_qty': reserved_qty,
'move_id': move.id,
'sale_line_id': move.sale_line_id.id if move.sale_line_id else False,
})
@@ -124,20 +121,26 @@ class PartialDeliveryWizard(models.TransientModel):
if not selected_lines:
raise UserError(_("Tidak ada produk yang dipilih atau diisi jumlahnya."))
- # ๐Ÿง  Tambahan: kalau semua line dipilih (full delivery)
- all_selected = len(selected_lines) == len(self.line_ids)
- full_selected = all_selected and all(
- (line.selected_qty or line.reserved_qty) >= line.reserved_qty
- for line in selected_lines
+ # ๐Ÿง  Cek apakah semua move di DO sudah muncul di wizard dan semua dipilih
+ picking_move_ids = picking.move_ids_without_package.ids
+ wizard_move_ids = self.line_ids.mapped('move_id').ids
+
+ # Semua move DO muncul di wizard, dan semua baris dipilih
+ full_selected = (
+ set(picking_move_ids) == set(wizard_move_ids)
+ and len(selected_lines) == len(self.line_ids)
+ and all(
+ (line.selected_qty or line.reserved_qty) >= line.reserved_qty
+ for line in selected_lines
+ )
)
if full_selected:
# ๐Ÿ’ก Gak perlu bikin picking baru, langsung ubah state_reserve
picking.write({'state_reserve': 'partial'})
- # Tambahin log aja biar ada jejak
picking.message_post(
- body=f"<b>Full Picking Confirmed</b> dari wizard partial delivery oleh {self.env.user.name}",
+ body=f"<b>Full Picking Confirmed</b> via wizard partial delivery oleh {self.env.user.name} (tanpa DO baru)",
message_type="comment",
subtype_xmlid="mail.mt_note",
)
@@ -150,11 +153,12 @@ class PartialDeliveryWizard(models.TransientModel):
"target": "current",
"effect": {
"fadeout": "slow",
- "message": f"โœ… Semua produk dikirim penuh โ€” tidak dibuat DO baru.",
+ "message": f"โœ… Semua produk dari DO ini dikirim penuh โ€” tidak dibuat DO baru.",
"type": "rainbow_man",
},
}
+ # ๐Ÿงฉ Kalau bukan full selected, lanjut bikin DO baru
new_picking = StockPicking.create({
'origin': picking.origin,
'partner_id': picking.partner_id.id,
@@ -171,11 +175,9 @@ class PartialDeliveryWizard(models.TransientModel):
move = line.move_id
move._do_unreserve()
- # kalau cuma selected tanpa isi qty, otomatis set selected_qty = reserved_qty
if line.selected and not line.selected_qty:
line.selected_qty = line.reserved_qty
- # MODE 1 โ†’ Prioritas kalau ada selected_qty
if line.selected_qty > 0:
if line.selected_qty > move.product_uom_qty:
raise UserError(_(
@@ -184,7 +186,6 @@ class PartialDeliveryWizard(models.TransientModel):
if line.selected_qty < move.product_uom_qty:
qty_to_keep = move.product_uom_qty - line.selected_qty
- # split move
new_move = move.copy(default={
'product_uom_qty': line.selected_qty,
'picking_id': new_picking.id,
@@ -192,35 +193,21 @@ class PartialDeliveryWizard(models.TransientModel):
})
move.write({'product_uom_qty': qty_to_keep})
else:
- # full pindah
move.write({'picking_id': new_picking.id, 'partial': True})
-
-
- # Confirm & assign DO baru
new_picking.action_confirm()
new_picking.action_assign()
-
- # Reassign DO lama biar sisa qty ke-update
picking.action_assign()
- # --- ๐Ÿ”ข Rename picking baru dengan format "/(Nomor urut)" ---
existing_partials = self.env['stock.picking'].search([
('origin', '=', picking.origin),
('state_reserve', '=', 'partial'),
('id', '!=', new_picking.id),
], order='name asc')
- suffix_number = len(existing_partials)
- if suffix_number == 0:
- suffix_number = 1
- else:
- suffix_number += 1
+ suffix_number = len(existing_partials) + 1
+ new_picking.name = f"{picking.name}/{suffix_number}"
- new_name = f"{picking.name}/{suffix_number}"
- new_picking.name = new_name
-
- # --- ๐Ÿ’ฌ Post message ke SO ---
if picking.origin:
sale_order = self.env['sale.order'].search([('name', '=', picking.origin)], limit=1)
if sale_order:
@@ -231,7 +218,6 @@ class PartialDeliveryWizard(models.TransientModel):
subtype_xmlid="mail.mt_note",
)
- # --- ๐Ÿ“ Log di DO baru ---
new_picking.message_post(
body=f"<b>Partial Picking created</b> dari {picking.name} oleh {self.env.user.name}",
message_type="comment",
@@ -251,8 +237,6 @@ class PartialDeliveryWizard(models.TransientModel):
},
}
-
-
class PartialDeliveryWizardLine(models.TransientModel):
_name = 'partial.delivery.wizard.line'
_description = 'Partial Delivery Wizard Line'
diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py
index b34ec926..e79417aa 100755
--- a/indoteknik_custom/models/purchase_order.py
+++ b/indoteknik_custom/models/purchase_order.py
@@ -1069,6 +1069,21 @@ class PurchaseOrder(models.Model):
) % order.name)
def button_confirm(self):
+ if self.env.user.id != 7 and not self.env.user.is_leader: # Pimpinan
+ if '/PJ/' in self.name:
+ low_margin_lines = self.order_sales_match_line.filtered(
+ lambda match: match.so_header_margin <= 15.0
+ )
+ price_change_detected = any(line.price_unit_before for line in self.order_line)
+ if low_margin_lines and price_change_detected:
+ # raise UserError("Matches SO terdapat item dengan header margin SO <= 15%. Approval Pimpinan diperlukan.")
+ raise UserError("Approval Pimpinan diperlukan jika terdapat perubahan Unit Price pada PO Line yang Matches SO item memiliki header margin SO <= 15%")
+ # else:
+ # is_po_manual = '/A/' not in self.name and '/MO/' not in self.name
+ # if is_po_manual:
+ # if not self.order_sales_match_line:
+ # raise UserError("Tidak ada matches SO, Approval Pimpinan diperlukan.")
+
self._check_assets_note()
# self._check_payment_term() # check payment term
res = super(PurchaseOrder, self).button_confirm()
@@ -1077,7 +1092,7 @@ class PurchaseOrder(models.Model):
self.check_different_vendor_so_po()
# self.check_data_vendor()
- if self.amount_untaxed >= 50000000 and not self.env.user.id == 21:
+ if self.amount_untaxed >= 50000000 and not self.env.user.id in (21, 7):
raise UserError("Hanya Rafly Hanggara yang bisa approve")
if not self.date_planned:
@@ -1405,63 +1420,50 @@ class PurchaseOrder(models.Model):
('product_id', '=', line.product_id.id),
('order_id', '=', line.purchase_order_id.id)
], limit=1)
- sale_order_line = line.sale_line_id
- if not sale_order_line:
- sale_order_line = self.env['sale.order.line'].search([
- ('product_id', '=', line.product_id.id),
- ('order_id', '=', line.sale_id.id)
- ], limit=1, order='price_reduce_taxexcl')
+ sale_order_line = line.sale_line_id or self.env['sale.order.line'].search([
+ ('product_id', '=', line.product_id.id),
+ ('order_id', '=', line.sale_id.id)
+ ], limit=1, order='price_reduce_taxexcl')
if sale_order_line and po_line:
- so_margin = (line.qty_po / line.qty_so) * sale_order_line.item_margin
+ qty_so = line.qty_so or 0
+ qty_po = line.qty_po or 0
+
+ # Hindari division by zero
+ so_margin = (qty_po / qty_so) * sale_order_line.item_margin if qty_so > 0 else 0
sum_so_margin += so_margin
- sales_price = sale_order_line.price_reduce_taxexcl * line.qty_po
+ sales_price = sale_order_line.price_reduce_taxexcl * qty_po
if sale_order_line.order_id.shipping_cost_covered == 'indoteknik':
- sales_price -= (sale_order_line.delivery_amt_line / sale_order_line.product_uom_qty) * line.qty_po
+ sales_price -= (sale_order_line.delivery_amt_line / sale_order_line.product_uom_qty) * qty_po
if sale_order_line.order_id.fee_third_party > 0:
- sales_price -= (sale_order_line.fee_third_party_line / sale_order_line.product_uom_qty) * line.qty_po
+ sales_price -= (sale_order_line.fee_third_party_line / sale_order_line.product_uom_qty) * qty_po
sum_sales_price += sales_price
-
purchase_price = po_line.price_subtotal
if po_line.ending_price > 0:
if po_line.taxes_id.id == 22:
- ending_price = po_line.ending_price / 1.11
- purchase_price = ending_price
+ purchase_price = po_line.ending_price / 1.11
else:
purchase_price = po_line.ending_price
if line.purchase_order_id.delivery_amount > 0:
- purchase_price += (po_line.delivery_amt_line / po_line.product_qty) * line.qty_po
+ purchase_price += (po_line.delivery_amt_line / po_line.product_qty) * qty_po
if line.purchase_order_id.delivery_amt > 0:
purchase_price += line.purchase_order_id.delivery_amt
+
real_item_margin = sales_price - purchase_price
sum_margin += real_item_margin
- if sum_so_margin != 0 and sum_sales_price != 0 and sum_margin != 0:
+ # Akumulasi hasil akhir
+ if sum_sales_price != 0:
self.total_so_margin = sum_so_margin
self.total_so_percent_margin = round((sum_so_margin / sum_sales_price), 2) * 100
self.total_margin = sum_margin
self.total_percent_margin = round((sum_margin / sum_sales_price), 2) * 100
-
else:
- self.total_margin = 0
- self.total_percent_margin = 0
- self.total_so_margin = 0
- self.total_so_percent_margin = 0
-
-
- if sum_so_margin != 0 and sum_sales_price != 0 and sum_margin != 0:
- self.total_so_margin = sum_so_margin
- self.total_so_percent_margin = round((sum_so_margin / sum_sales_price), 2) * 100
- self.total_margin = sum_margin
- self.total_percent_margin = round((sum_margin / sum_sales_price), 2) * 100
+ self.total_margin = self.total_percent_margin = 0
+ self.total_so_margin = self.total_so_percent_margin = 0
- else:
- self.total_margin = 0
- self.total_percent_margin = 0
- self.total_so_margin = 0
- self.total_so_percent_margin = 0
def compute_amt_total_without_service(self):
for order in self:
diff --git a/indoteknik_custom/models/purchase_order_line.py b/indoteknik_custom/models/purchase_order_line.py
index a3c3a33b..8c72887d 100755
--- a/indoteknik_custom/models/purchase_order_line.py
+++ b/indoteknik_custom/models/purchase_order_line.py
@@ -51,6 +51,12 @@ class PurchaseOrderLine(models.Model):
contribution_cost_service = fields.Float(string='Contribution Cost Service', compute='_compute_doc_delivery_amt')
ending_price = fields.Float(string='Ending Price', compute='_compute_doc_delivery_amt')
show_description = fields.Boolean(string='Show Description', help="Show Description when print po", default=True)
+ price_unit_before = fields.Float(string='Unit Price Before', help="Harga awal yang sebelumnya telah diinputkan")
+
+ @api.onchange('price_unit')
+ def _onchange_price_unit_before(self):
+ if self._origin:
+ self.price_unit_before = self._origin.price_unit
def _compute_doc_delivery_amt(self):
for line in self:
diff --git a/indoteknik_custom/models/purchase_order_sales_match.py b/indoteknik_custom/models/purchase_order_sales_match.py
index 084b93f7..ea25a3b1 100644
--- a/indoteknik_custom/models/purchase_order_sales_match.py
+++ b/indoteknik_custom/models/purchase_order_sales_match.py
@@ -29,6 +29,11 @@ class PurchaseOrderSalesMatch(models.Model):
purchase_line_id = fields.Many2one('purchase.order.line', string='Purchase Line', compute='_compute_purchase_line_id')
hold_outgoing_so = fields.Boolean(string='Hold Outgoing SO', related='sale_id.hold_outgoing')
bu_pick = fields.Many2one('stock.picking', string='BU Pick', compute='compute_bu_pick')
+ so_header_margin = fields.Float(
+ related='sale_id.total_percent_margin',
+ string='SO Header Margin %',
+ readonly=True
+ )
def compute_bu_pick(self):
for rec in self:
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index 4a7203a1..a5e2f7c4 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -3230,6 +3230,10 @@ class SaleOrder(models.Model):
# order._auto_set_shipping_from_website()
order._compute_etrts_date()
order._validate_expected_ready_ship_date()
+ # for line in order.order_line:
+ # updated_vals = line._update_purchase_info()
+ # if updated_vals:
+ # line.write(updated_vals)
# order._validate_delivery_amt()
# order._check_total_margin_excl_third_party()
# order._update_partner_details()
@@ -3361,6 +3365,12 @@ class SaleOrder(models.Model):
if any(field in vals for field in ["order_line", "client_order_ref"]):
self._calculate_etrts_date()
+ # for order in self:
+ # for line in order.order_line:
+ # updated_vals = line._update_purchase_info()
+ # if updated_vals:
+ # line.write(updated_vals)
+
return res
def button_refund(self):
diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py
index 1f2ea1fb..1df1a058 100644
--- a/indoteknik_custom/models/sale_order_line.py
+++ b/indoteknik_custom/models/sale_order_line.py
@@ -247,29 +247,29 @@ class SaleOrderLine(models.Model):
margin_per_item = sales_price - purchase_price
line.item_before_margin = margin_per_item
- @api.onchange('vendor_id')
- def onchange_vendor_id(self):
- # TODO : need to change this logic @stephan
- if not self.product_id or self.product_id.type == 'service':
- return
- elif self.product_id.categ_id.id == 34: # finish good / manufacturing only
- cost = self.product_id.standard_price
- self.purchase_price = cost
- elif self.product_id.x_manufacture.override_vendor_id:
- # purchase_price = self.env['purchase.pricelist'].search(
- # [('vendor_id', '=', self.product_id.x_manufacture.override_vendor_id.id),
- # ('product_id', '=', self.product_id.id)],
- # limit=1, order='count_trx_po desc, count_trx_po_vendor desc')
- price, taxes, vendor_id = self._get_purchase_price_by_vendor(self.product_id, self.vendor_id)
- self.purchase_price = price
- self.purchase_tax_id = taxes
- # else:
- # purchase_price = self.env['purchase.pricelist'].search(
- # [('vendor_id', '=', self.vendor_id.id), ('product_id', '=', self.product_id.id)],
- # limit=1, order='count_trx_po desc, count_trx_po_vendor desc')
- # price, taxes = self._get_valid_purchase_price(purchase_price)
- # self.purchase_price = price
- # self.purchase_tax_id = taxes
+ # @api.onchange('vendor_id')
+ # def onchange_vendor_id(self):
+ # # TODO : need to change this logic @stephan
+ # if not self.product_id or self.product_id.type == 'service':
+ # return
+ # elif self.product_id.categ_id.id == 34: # finish good / manufacturing only
+ # cost = self.product_id.standard_price
+ # self.purchase_price = cost
+ # elif self.product_id.x_manufacture.override_vendor_id:
+ # # purchase_price = self.env['purchase.pricelist'].search(
+ # # [('vendor_id', '=', self.product_id.x_manufacture.override_vendor_id.id),
+ # # ('product_id', '=', self.product_id.id)],
+ # # limit=1, order='count_trx_po desc, count_trx_po_vendor desc')
+ # price, taxes, vendor_id = self._get_purchase_price_by_vendor(self.product_id, self.vendor_id)
+ # self.purchase_price = price
+ # self.purchase_tax_id = taxes
+ # # else:
+ # # purchase_price = self.env['purchase.pricelist'].search(
+ # # [('vendor_id', '=', self.vendor_id.id), ('product_id', '=', self.product_id.id)],
+ # # limit=1, order='count_trx_po desc, count_trx_po_vendor desc')
+ # # price, taxes = self._get_valid_purchase_price(purchase_price)
+ # # self.purchase_price = price
+ # # self.purchase_tax_id = taxes
# def _calculate_selling_price(self):
# rec_purchase_price, rec_taxes, rec_vendor_id = self._get_purchase_price(self.product_id)
@@ -512,3 +512,19 @@ class SaleOrderLine(models.Model):
else:
line.product_updatable = False
# line.desc_updatable = False
+
+ @api.onchange('vendor_id')
+ def _onchange_vendor_id_custom(self):
+ self._update_purchase_info()
+
+ def _update_purchase_info(self):
+ if not self.product_id or self.product_id.type == 'service':
+ return
+
+ if self.product_id.categ_id.id == 34:
+ self.purchase_price = self.product_id.standard_price
+ self.purchase_tax_id = False
+ elif self.product_id.x_manufacture.override_vendor_id:
+ price, taxes, vendor_id = self._get_purchase_price_by_vendor(self.product_id, self.vendor_id)
+ self.purchase_price = price
+ self.purchase_tax_id = taxes
diff --git a/indoteknik_custom/models/sj_tele.py b/indoteknik_custom/models/sj_tele.py
index 3ef4b877..53ba26fc 100644
--- a/indoteknik_custom/models/sj_tele.py
+++ b/indoteknik_custom/models/sj_tele.py
@@ -18,6 +18,7 @@ class SjTele(models.Model):
sale_name = fields.Char(string='Sale Name')
create_date = fields.Datetime(string='Create Date')
date_doc_kirim = fields.Datetime(string='Tanggal Kirim SJ')
+ is_sent = fields.Boolean(default=False)
def woi(self):
bot_mqdd = '8203414501:AAHy_XwiUAVrgRM2EJzW7sZx9npRLITZpb8'
@@ -27,7 +28,11 @@ class SjTele(models.Model):
# chat_id_testing = '-4920864331'
# api_testing = f'https://api.telegram.org/bot{bot_testing}'
- data = self.search([], order='create_date asc')
+ # Select Data
+ data = self.search([('is_sent', '=', False)], order='create_date asc')
+
+ # Old
+ # data = self.search([], order='create_date asc')
if not data:
text = "โœ… tidak ada data (semua sudah tercatat)."
@@ -83,6 +88,9 @@ class SjTele(models.Model):
_logger.exception("Gagal kirim Telegram (batch %s-%s): %s", i + 1, min(i + BUB, len(lines)), e)
time.sleep(5) # jeda kecil biar rapi & aman rate limit
+ # Set sent = true ketika sudah terkirim
+ data.write({'is_sent': True})
+
return True
# header = "Berikut merupakan nomor BU/OUT yang belum ada di Logbook SJ report:\n"
diff --git a/indoteknik_custom/models/stock_move.py b/indoteknik_custom/models/stock_move.py
index b7db8775..1da2befe 100644
--- a/indoteknik_custom/models/stock_move.py
+++ b/indoteknik_custom/models/stock_move.py
@@ -21,6 +21,14 @@ class StockMove(models.Model):
product_image = fields.Binary(related="product_id.image_128", string="Product Image", readonly=True)
partial = fields.Boolean('Partial?', default=False)
+ # Ambil product uom dari SO line
+ @api.model
+ def create(self, vals):
+ if vals.get('sale_line_id'):
+ sale_line = self.env['sale.order.line'].browse(vals['sale_line_id'])
+ vals['product_uom'] = sale_line.product_uom.id
+ return super().create(vals)
+
# @api.model_create_multi
# def create(self, vals_list):
# moves = super(StockMove, self).create(vals_list)
@@ -178,3 +186,12 @@ class StockMoveLine(models.Model):
line_no = fields.Integer('No', default=0)
note = fields.Char('Note')
manufacture = fields.Many2one('x_manufactures', string="Brands", related="product_id.x_manufacture", store=True)
+
+ # Ambil uom dari stock move
+ @api.model
+ def create(self, vals):
+ if 'move_id' in vals and 'product_uom_id' not in vals:
+ move = self.env['stock.move'].browse(vals['move_id'])
+ if move.product_uom:
+ vals['product_uom_id'] = move.product_uom.id
+ return super().create(vals) \ No newline at end of file
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index 4772c433..d6096cc0 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -464,15 +464,15 @@ class StockPicking(models.Model):
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")
+ # @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
+ # picking.driver_departure_date = now
@api.depends('total_so_koli')
def _compute_total_so_koli(self):
@@ -1303,6 +1303,9 @@ class StockPicking(models.Model):
and self.create_date > threshold_datetime
and not self.so_lama):
raise UserError(_("Tidak ada scan koli! Harap periksa kembali."))
+
+ if 'BU/OUT/' in self.name:
+ self.driver_departure_date = datetime.datetime.utcnow()
# if self.driver_departure_date == False and 'BU/OUT/' in self.name and self.picking_type_code == 'outgoing':
# raise UserError(_("Isi Driver Departure Date dulu sebelum validate"))
diff --git a/indoteknik_custom/views/account_asset_views.xml b/indoteknik_custom/views/account_asset_views.xml
index 90c53623..776ab51f 100644
--- a/indoteknik_custom/views/account_asset_views.xml
+++ b/indoteknik_custom/views/account_asset_views.xml
@@ -12,6 +12,9 @@
type="object"
/>
</button>
+ <field name="invoice_id" position="after">
+ <field name="asset_type"/>
+ </field>
</field>
</record>
</data>
diff --git a/indoteknik_custom/views/purchase_order.xml b/indoteknik_custom/views/purchase_order.xml
index 7feec934..09d901b9 100755
--- a/indoteknik_custom/views/purchase_order.xml
+++ b/indoteknik_custom/views/purchase_order.xml
@@ -144,6 +144,7 @@
<field name="cost_service_per_item" optional="hide"/>
<field name="contribution_cost_service" optional="hide"/>
<field name="ending_price" optional="hide"/>
+ <field name="price_unit_before" readonly="1" optional="hide" force_save="1"/>
<!-- <field name="suggest" readonly="1"/> -->
</field>
<field name="product_id" position="before">
@@ -390,6 +391,7 @@
<field name="hold_outgoing_so" optional="hide"/>
<field name="bu_pick" optional="hide"/>
<field name="margin_so"/>
+ <field name="so_header_margin" optional="hide"/>
</tree>
</field>
</record>