diff options
| author | FIN-IT_AndriFP <it@fixcomart.co.id> | 2025-10-23 09:50:40 +0700 |
|---|---|---|
| committer | FIN-IT_AndriFP <it@fixcomart.co.id> | 2025-10-23 09:50:40 +0700 |
| commit | 310f92c9b825a458618daa3b00581b790f8e009e (patch) | |
| tree | 2b8957db596c86525c009ef5e62e23ccd6397f8f | |
| parent | 58a6ca75b9b1bb07ea958ab4bfb553140daeb8f8 (diff) | |
| parent | 8d649f97dade329859b5770d1f3972cdd7233f97 (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.py | 14 | ||||
| -rw-r--r-- | indoteknik_api/controllers/api_v1/stock_picking.py | 12 | ||||
| -rw-r--r-- | indoteknik_custom/models/account_asset.py | 4 | ||||
| -rw-r--r-- | indoteknik_custom/models/commision.py | 8 | ||||
| -rw-r--r-- | indoteknik_custom/models/mrp_production.py | 3 | ||||
| -rw-r--r-- | indoteknik_custom/models/partial_delivery.py | 52 | ||||
| -rwxr-xr-x | indoteknik_custom/models/purchase_order.py | 68 | ||||
| -rwxr-xr-x | indoteknik_custom/models/purchase_order_line.py | 6 | ||||
| -rw-r--r-- | indoteknik_custom/models/purchase_order_sales_match.py | 5 | ||||
| -rwxr-xr-x | indoteknik_custom/models/sale_order.py | 10 | ||||
| -rw-r--r-- | indoteknik_custom/models/sale_order_line.py | 62 | ||||
| -rw-r--r-- | indoteknik_custom/models/sj_tele.py | 10 | ||||
| -rw-r--r-- | indoteknik_custom/models/stock_move.py | 17 | ||||
| -rw-r--r-- | indoteknik_custom/models/stock_picking.py | 19 | ||||
| -rw-r--r-- | indoteknik_custom/views/account_asset_views.xml | 3 | ||||
| -rwxr-xr-x | indoteknik_custom/views/purchase_order.xml | 2 |
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> |
