From ddc06e464075c316de8f236e0e037dd964a972e3 Mon Sep 17 00:00:00 2001 From: Miqdad Date: Thu, 6 Nov 2025 10:16:52 +0700 Subject: add new field --- indoteknik_custom/models/stock_picking.py | 44 +++++++++++++++----------- indoteknik_custom/security/ir.model.access.csv | 1 + indoteknik_custom/views/stock_picking.xml | 19 +++++++++-- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index c17fdbd5..04847be8 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -89,6 +89,7 @@ class StockPicking(models.Model): readonly=True, related="id", ) + sj_documentations = fields.One2many('stock.picking.sj.document','picking_id', string='Dokumentasi SJ (Multi)') sj_documentation = fields.Binary(string="Dokumentasi Surat Jalan") paket_documentation = fields.Binary(string="Dokumentasi Paket") dispatch_documentation = fields.Binary(string="Dokumentasi Dispatch") @@ -205,8 +206,6 @@ class StockPicking(models.Model): for record in self: record.so_num = record.group_id.name - - @api.depends('move_line_ids_without_package.qty_done', 'move_line_ids_without_package.product_uom_qty', 'state') def _compute_delivery_status_detail(self): for picking in self: @@ -468,7 +467,6 @@ class StockPicking(models.Model): except ValueError: return False - def action_get_kgx_pod(self, shipment=False): self.ensure_one() @@ -1189,7 +1187,8 @@ class StockPicking(models.Model): self.sale_id.date_doc_kirim = self.date_doc_kirim def action_assign(self): - if self.env.context.get('default_picking_type_id') and ('BU/INPUT' not in self.name or 'BU/PUT' not in self.name): + if self.env.context.get('default_picking_type_id') and ( + 'BU/INPUT' not in self.name or 'BU/PUT' not in self.name): pickings_to_assign = self.filtered( lambda p: not (p.sale_id and p.sale_id.hold_outgoing) ) @@ -1205,18 +1204,15 @@ class StockPicking(models.Model): return res - def ask_approval(self): # if self.env.user.is_accounting: # if self.env.user.is_accounting and self.location_id.id == 57 or self.location_id == 57 and self.approval_status in ['pengajuan1', ''] and 'BU/IU' in self.name and self.approval_status == 'pengajuan1': # raise UserError("Bisa langsung set ke approval logistik") if self.env.user.is_accounting and self.approval_status == "pengajuan2" and 'BU/IU' in self.name: raise UserError("Tidak perlu ask approval sudah approval logistik") - if self.env.user.is_logistic_approver and self.location_id.id == 57 or self.location_id== 57 and self.approval_status == 'pengajuan2' and 'BU/IU' in self.name: + if self.env.user.is_logistic_approver and self.location_id.id == 57 or self.location_id == 57 and self.approval_status == 'pengajuan2' and 'BU/IU' in self.name: raise UserError("Bisa langsung Validate") - - # for calendar distribute only # if self.is_internal_use: # stock_move_lines = self.env['stock.move.line'].search([ @@ -1239,7 +1235,6 @@ class StockPicking(models.Model): raise UserError("Qty tidak boleh 0") pick.approval_status = 'pengajuan1' - def ask_receipt_approval(self): if self.env.user.is_logistic_approver: raise UserError('Bisa langsung validate tanpa Ask Receipt') @@ -1405,7 +1400,7 @@ 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() @@ -1447,13 +1442,16 @@ class StockPicking(models.Model): # if self.is_internal_use and not self.env.user.is_logistic_approver and self.location_id.id == 57 and self.approval_status == 'pengajuan2': # raise UserError("Harus di Approve oleh Logistik") - if self.is_internal_use and self.approval_status in ['pengajuan1', '', False] and 'BU/IU' in self.name and self.is_bu_iu == True: + if self.is_internal_use and self.approval_status in ['pengajuan1', '', + False] and 'BU/IU' in self.name and self.is_bu_iu == True: raise UserError("Tidak Bisa Validate, set approval status ke approval logistik terlebih dahhulu") - if self.is_internal_use and not self.env.user.is_logistic_approver and self.approval_status in ['pengajuan2'] and self.is_bu_iu == True and 'BU/IU' in self.name: + if self.is_internal_use and not self.env.user.is_logistic_approver and self.approval_status in [ + 'pengajuan2'] and self.is_bu_iu == True and 'BU/IU' in self.name: raise UserError("Harus di Approve oleh Logistik") - if self.is_internal_use and not self.env.user.is_accounting and self.approval_status in ['pengajuan1', '', False] and self.is_bu_iu == False: + if self.is_internal_use and not self.env.user.is_accounting and self.approval_status in ['pengajuan1', '', + False] and self.is_bu_iu == False: raise UserError("Harus di Approve oleh Accounting") if self.picking_type_id.id == 28 and not self.env.user.is_logistic_approver: @@ -1479,7 +1477,6 @@ class StockPicking(models.Model): current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') self.date_reserved = current_time - # Validate Qty Demand Can't higher than Qty Product if self.location_dest_id.id == 58 and 'BU/INPUT/' in self.name: for move in self.move_ids_without_package: @@ -1880,7 +1877,8 @@ class StockPicking(models.Model): 'name': move_line.product_id.name, 'code': move_line.product_id.default_code, 'qty': move_line.qty_done, - 'image': self.env['ir.attachment'].api_image('product.template', 'image_128', move_line.product_id.product_tmpl_id.id), + 'image': self.env['ir.attachment'].api_image('product.template', 'image_128', + move_line.product_id.product_tmpl_id.id), }) response = { @@ -2246,7 +2244,6 @@ class CheckProduct(models.Model): _order = 'picking_id, id' _inherit = ['barcodes.barcode_events_mixin'] - picking_id = fields.Many2one( 'stock.picking', string='Picking Reference', @@ -2699,8 +2696,6 @@ class ScanKoli(models.Model): out_move.qty_done += qty_to_assign qty_koli -= qty_to_assign - - def _reset_qty_done_if_no_scan(self, picking_id): product_bu_pick = self.env['stock.move.line'].search([('picking_id', '=', picking_id)]) @@ -2759,4 +2754,15 @@ class WarningModalWizard(models.TransientModel): def action_continue(self): if self.picking_id: return self.picking_id.with_context(skip_koli_check=True).button_validate() - return {'type': 'ir.actions.act_window_close'} \ No newline at end of file + return {'type': 'ir.actions.act_window_close'} + + +class StockPickingSjDocument(models.Model): + _name = 'stock.picking.sj.document' + _description = 'Dokumentasi Surat Jalan (Multi)' + _order = 'sequence, id' + _rec_name = 'id' + + picking_id = fields.Many2one('stock.picking', required=True, ondelete='cascade') + image = fields.Binary('Gambar', required=True, attachment=True) + sequence = fields.Integer('Urutan', default=10) \ No newline at end of file diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index c01271d3..dadc2c82 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -210,3 +210,4 @@ access_unpaid_invoice_view,access.unpaid.invoice.view,model_unpaid_invoice_view, access_surat_piutang_user,surat.piutang user,model_surat_piutang,,1,1,1,1 access_surat_piutang_line_user,surat.piutang.line user,model_surat_piutang_line,,1,1,1,1 access_sj_tele,access.sj.tele,model_sj_tele,base.group_system,1,1,1,1 +access_stock_picking_sj_document,stock.picking.sj.document,model_stock_picking_sj_document,base.group_system,1,1,1,1 diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml index cc9469cb..2925cf2c 100644 --- a/indoteknik_custom/views/stock_picking.xml +++ b/indoteknik_custom/views/stock_picking.xml @@ -166,7 +166,7 @@ - + @@ -249,6 +249,16 @@ attrs="{'invisible': [('select_shipping_option_so', '=', 'biteship')]}"/> + + + + +
+ + + +
+
@@ -402,7 +412,8 @@ - + @@ -426,7 +437,9 @@
-

⚠️ Perhatian!

+

+ ⚠️ Perhatian! +

-- cgit v1.2.3 From 73908f6f60b4c5f3d7b7cd3a1a3ab04495de2047 Mon Sep 17 00:00:00 2001 From: Miqdad Date: Thu, 6 Nov 2025 13:38:58 +0700 Subject: cr ask approval admin --- indoteknik_custom/models/sale_order.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index ff79761c..73af811b 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -2363,15 +2363,6 @@ class SaleOrder(models.Model): 'Peringatan', 'Hanya bisa konfirmasi SO tim Anda.' ) - if self.env.user.id in (3401, 20, 3988, 17340): - if self.total_percent_margin <= 15: - self._requires_approval_margin_leader() - self.approval_status = 'pengajuan2' - elif self.total_percent_margin < 18: - self._requires_approval_margin_manager() - self.approval_status = 'pengajuan1' - elif 18 <= self.total_percent_margin <= 24: - self._requires_approval_team_sales() raise UserError("Bisa langsung Confirm") @@ -2712,7 +2703,7 @@ class SaleOrder(models.Model): def _requires_approval_team_sales(self): return ( - 18 <= self.total_percent_margin <= 24 + self.total_percent_margin >= 18 and self.env.user.id not in [11, 9, 375] # Eko, Ade, Putra and not self.env.user.is_sales_manager and not self.env.user.is_leader -- cgit v1.2.3 From aad9e13e0a1908dc8d14d86dfc67bdf9f8e006e7 Mon Sep 17 00:00:00 2001 From: Miqdad Date: Thu, 6 Nov 2025 14:49:02 +0700 Subject: api --- indoteknik_api/controllers/api_v1/stock_picking.py | 86 ++++++++++++++++++---- 1 file changed, 72 insertions(+), 14 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/stock_picking.py b/indoteknik_api/controllers/api_v1/stock_picking.py index fe82e665..a03016c5 100644 --- a/indoteknik_api/controllers/api_v1/stock_picking.py +++ b/indoteknik_api/controllers/api_v1/stock_picking.py @@ -121,38 +121,96 @@ class StockPicking(controller.Controller): return self.response(picking.get_tracking_detail()) + from datetime import datetime + from odoo import http + from odoo.http import request + @http.route(prefix + 'stock-picking//documentation', auth='public', methods=['PUT', 'OPTIONS'], csrf=False) @controller.Controller.must_authorized() def write_partner_stock_picking_documentation(self, scanid, **kw): - 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 + self_pu = kw.get('self_pu') if 'self_pu' in kw else None # ===== Cari picking by id / picking_code ===== - picking_data = False + picking = False if scanid.isdigit() and int(scanid) < 2147483646: - picking_data = request.env['stock.picking'].search([('id', '=', int(scanid))], limit=0) + picking = request.env['stock.picking'].search([('id', '=', int(scanid))], limit=0) + if not picking: + picking = request.env['stock.picking'].search([('picking_code', '=', scanid)], limit=0) + if not picking: + return self.response(code=403, description='picking not found') - if not picking_data: - picking_data = request.env['stock.picking'].search([('picking_code', '=', scanid)], limit=0) + # ===== Ambil MULTIPLE SJ dari form: sj_documentations=...&sj_documentations=... ===== + form = request.httprequest.form or {} + sj_list = form.getlist('sj_documentations') # list of base64 strings - if not picking_data: - return self.response(code=403, description='picking not found') + # fallback: kalau FE kirim single dengan nama yang sama (bukan list) + if not sj_list and 'sj_documentations' in kw and kw.get('sj_documentations'): + sj_list = [kw.get('sj_documentations')] + # ===== Tulis field lain yang dikirim (merge, bukan replace) ===== 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 + if sj_list and self_pu: + params['driver_arrival_date'] = datetime.utcnow() - picking_data.write(params) - return self.response({'name': picking_data.name}) + if params: + picking.write(params) + + # ===== Buat child rows utk SEMUA foto SJ ke One2many ===== + if sj_list: + Child = request.env['stock.picking.sj.document'].sudo() + # kasih urutan lanjut 10-10 + seq = (picking.sj_documentations[:1].sequence or 10) if picking.sj_documentations else 10 + for b64 in sj_list: + if not b64: + continue + Child.create({ + 'picking_id': picking.id, + 'sequence': seq, + 'image': b64, # base64 tanpa prefix + }) + seq += 10 + + return self.response({'name': picking.name}) + + # @http.route(prefix + 'stock-picking//documentation', auth='public', methods=['PUT', 'OPTIONS'], csrf=False) + # @controller.Controller.must_authorized() + # def write_partner_stock_picking_documentation(self, scanid, **kw): + # 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 + # if scanid.isdigit() and int(scanid) < 2147483646: + # picking_data = request.env['stock.picking'].search([('id', '=', int(scanid))], limit=0) + # + # if not picking_data: + # picking_data = request.env['stock.picking'].search([('picking_code', '=', scanid)], limit=0) + # + # if not picking_data: + # return self.response(code=403, description='picking not found') + # + # 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) -- cgit v1.2.3 From 062c606f4c31ee0966a6c08f4f3de52d719df883 Mon Sep 17 00:00:00 2001 From: Miqdad Date: Thu, 6 Nov 2025 15:35:54 +0700 Subject: update --- indoteknik_api/controllers/api_v1/stock_picking.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/stock_picking.py b/indoteknik_api/controllers/api_v1/stock_picking.py index a03016c5..c19812f5 100644 --- a/indoteknik_api/controllers/api_v1/stock_picking.py +++ b/indoteknik_api/controllers/api_v1/stock_picking.py @@ -121,10 +121,6 @@ class StockPicking(controller.Controller): return self.response(picking.get_tracking_detail()) - from datetime import datetime - from odoo import http - from odoo.http import request - @http.route(prefix + 'stock-picking//documentation', auth='public', methods=['PUT', 'OPTIONS'], csrf=False) @controller.Controller.must_authorized() def write_partner_stock_picking_documentation(self, scanid, **kw): @@ -149,7 +145,6 @@ class StockPicking(controller.Controller): if not sj_list and 'sj_documentations' in kw and kw.get('sj_documentations'): sj_list = [kw.get('sj_documentations')] - # ===== Tulis field lain yang dikirim (merge, bukan replace) ===== params = {} if paket_document: params['paket_documentation'] = paket_document @@ -162,10 +157,8 @@ class StockPicking(controller.Controller): if params: picking.write(params) - # ===== Buat child rows utk SEMUA foto SJ ke One2many ===== if sj_list: Child = request.env['stock.picking.sj.document'].sudo() - # kasih urutan lanjut 10-10 seq = (picking.sj_documentations[:1].sequence or 10) if picking.sj_documentations else 10 for b64 in sj_list: if not b64: @@ -173,7 +166,7 @@ class StockPicking(controller.Controller): Child.create({ 'picking_id': picking.id, 'sequence': seq, - 'image': b64, # base64 tanpa prefix + 'image': b64, }) seq += 10 -- cgit v1.2.3 From 704f27afd94787260543a2b6fed2ecfa13e786cb Mon Sep 17 00:00:00 2001 From: Miqdad Date: Tue, 11 Nov 2025 16:01:14 +0700 Subject: fix coretax xml --- indoteknik_custom/models/coretax_fatur.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/indoteknik_custom/models/coretax_fatur.py b/indoteknik_custom/models/coretax_fatur.py index 7e0de919..cabcd5d6 100644 --- a/indoteknik_custom/models/coretax_fatur.py +++ b/indoteknik_custom/models/coretax_fatur.py @@ -148,8 +148,6 @@ class CoretaxFaktur(models.Model): quantity = line_quantity total_discount = round(line_discount, 2) coretax_id = line.product_uom_id.coretax_id - uom_name = line.product_uom_id.name - # Calculate other tax values otherTaxBase = round(subtotal * (11 / 12), 2) if subtotal else 0 vat_amount = round(otherTaxBase * 0.12, 2) @@ -161,7 +159,7 @@ class CoretaxFaktur(models.Model): ET.SubElement(good_service, 'Opt').text = 'A' ET.SubElement(good_service, 'Code').text = '000000' ET.SubElement(good_service, 'Name').text = line_name - ET.SubElement(good_service, uom_name).text = coretax_id + ET.SubElement(good_service, 'Unit').text = coretax_id # ET.SubElement(good_service, 'Price').text = str(round(line_price_unit, 2)) if line_price_unit else '0' ET.SubElement(good_service, 'Price').text = str(price_per_unit) ET.SubElement(good_service, 'Qty').text = str(quantity) -- cgit v1.2.3 From 5e82281428e5297841179b4b9940e64d7e506815 Mon Sep 17 00:00:00 2001 From: Miqdad Date: Tue, 11 Nov 2025 18:32:53 +0700 Subject: fix ir access --- indoteknik_custom/security/ir.model.access.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index dadc2c82..caafc4aa 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -210,4 +210,4 @@ access_unpaid_invoice_view,access.unpaid.invoice.view,model_unpaid_invoice_view, access_surat_piutang_user,surat.piutang user,model_surat_piutang,,1,1,1,1 access_surat_piutang_line_user,surat.piutang.line user,model_surat_piutang_line,,1,1,1,1 access_sj_tele,access.sj.tele,model_sj_tele,base.group_system,1,1,1,1 -access_stock_picking_sj_document,stock.picking.sj.document,model_stock_picking_sj_document,base.group_system,1,1,1,1 +access_stock_picking_sj_document,stock.picking.sj.document,model_stock_picking_sj_document,1,1,1,1 -- cgit v1.2.3 From 9b983054e1aca39139e47f717c425090659ed3e3 Mon Sep 17 00:00:00 2001 From: Miqdad Date: Tue, 11 Nov 2025 18:36:15 +0700 Subject: fix ir access --- indoteknik_custom/security/ir.model.access.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index caafc4aa..0529db82 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -210,4 +210,4 @@ access_unpaid_invoice_view,access.unpaid.invoice.view,model_unpaid_invoice_view, access_surat_piutang_user,surat.piutang user,model_surat_piutang,,1,1,1,1 access_surat_piutang_line_user,surat.piutang.line user,model_surat_piutang_line,,1,1,1,1 access_sj_tele,access.sj.tele,model_sj_tele,base.group_system,1,1,1,1 -access_stock_picking_sj_document,stock.picking.sj.document,model_stock_picking_sj_document,1,1,1,1 +access_stock_picking_sj_document,stock.picking.sj.document,model_stock_picking_sj_document,base.group_user,1,1,1,1 -- cgit v1.2.3