diff options
| author | IT Fixcomart <it@fixcomart.co.id> | 2025-06-09 04:48:12 +0000 |
|---|---|---|
| committer | IT Fixcomart <it@fixcomart.co.id> | 2025-06-09 04:48:12 +0000 |
| commit | f43855aa55265794c7774af79089258e830b0df4 (patch) | |
| tree | ec0c4595d5c6eed250648613c7d46d6b583a33c7 | |
| parent | 9228e331a2b4c3f80eb22ec824a14633b6235972 (diff) | |
| parent | de747091235c844d33bcf62b4d98af0d03251826 (diff) | |
Merged in parsial-biteship (pull request #324)
Parsial biteship
| -rwxr-xr-x | indoteknik_custom/models/sale_order.py | 53 | ||||
| -rw-r--r-- | indoteknik_custom/models/stock_picking.py | 109 | ||||
| -rw-r--r-- | indoteknik_custom/views/stock_picking.xml | 2 |
3 files changed, 95 insertions, 69 deletions
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 3e340c60..80a552fe 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -256,6 +256,20 @@ class SaleOrder(models.Model): ('custom', 'Custom'), ], string='Shipping Option', help="Select shipping option for delivery", tracking=True) + @api.onchange('shipping_cost_covered') + def _onchange_shipping_cost_covered(self): + if self.shipping_cost_covered == 'indoteknik' and self.select_shipping_option == 'biteship': + self.shipping_cost_covered = 'customer' + return { + 'warning': { + 'title': "Biteship Tidak Diizinkan", + 'message': ( + "Biaya pengiriman ditanggung Indoteknik, sehingga tidak diizinkan menggunakan metode Biteship. " + "Pilihan penanggung biaya akan dikembalikan sebelumnya" + ) + } + } + def get_biteship_carrier_ids(self): courier_codes = tuple(self._get_biteship_courier_codes() or []) if not courier_codes: @@ -277,20 +291,29 @@ class SaleOrder(models.Model): if view_type == 'form': doc = etree.XML(res['arch']) - carrier_ids = self.get_biteship_carrier_ids() - if carrier_ids: - carrier_ids_str = '(' + ','.join(str(x) for x in carrier_ids) + ')' - else: - carrier_ids_str = '(-1,)' # aman kalau kosong + # Ambil semua delivery_carrier_id dari mapping rajaongkir_kurir + biteship_ids = self.env['rajaongkir.kurir'].search([]).mapped('delivery_carrier_id.id') + biteship_ids = list(set(filter(None, biteship_ids))) # pastikan unik dan bukan None + + all_ids = self.env['delivery.carrier'].search([]).ids + custom_ids = list(set(all_ids) - set(biteship_ids)) - # ✅ Tambahkan log di sini - _logger.info("🛰️ Biteship Carrier IDs: %s", carrier_ids) - _logger.info("📦 Domain string to apply: [('id', 'in', %s)]", carrier_ids_str) + # Format sebagai string Python list + biteship_ids_str = ','.join(str(i) for i in biteship_ids) or '-1' + custom_ids_str = ','.join(str(i) for i in custom_ids) or '-1' + # Terapkan domain ke field carrier_id for node in doc.xpath("//field[@name='carrier_id']"): - node.set('domain', "[('id', 'in', %s)]" % carrier_ids_str) + # Domain tergantung select_shipping_option + node.set( + 'domain', + "[('id', 'in', [%s]) if select_shipping_option == 'biteship' else ('id', 'in', [%s])]" % + (biteship_ids_str, custom_ids_str) + ) + # Simpan kembali hasil XML ke arsitektur form res['arch'] = etree.tostring(doc, encoding='unicode') + return res # @api.onchange('shipping_option_id') @@ -470,6 +493,18 @@ class SaleOrder(models.Model): @api.onchange('select_shipping_option') def _onchange_select_shipping_option(self): + if self.select_shipping_option == 'biteship' and self.shipping_cost_covered == 'indoteknik': + self.select_shipping_option = self._origin.select_shipping_option if self._origin else 'custom' + return { + 'warning': { + 'title': "Biteship Tidak Diizinkan", + 'message': ( + "Biaya pengiriman ditanggung Indoteknik. Tidak diizinkan memilih metode Biteship. " + "Opsi pengiriman dikembalikan ke sebelumnya." + ) + } + } + self.shipping_option_id = False self.carrier_id = False self.delivery_amt = 0 diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index a2935a07..d04b3d27 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -244,6 +244,11 @@ class StockPicking(models.Model): biteship_waybill_id = fields.Char(string="Biteship Waybill ID") final_seq = fields.Float(string='Remaining Time') shipping_method_so_id = fields.Many2one('delivery.carrier', string='Shipping Method SO', related='sale_id.carrier_id') + shipping_option_so_id = fields.Many2one('shipping.option', string='Shipping Option SO', related='sale_id.shipping_option_id') + select_shipping_option_so = fields.Selection([ + ('biteship', 'Biteship'), + ('custom', 'Custom'), + ], string='Shipping Type SO', related='sale_id.select_shipping_option') state_packing = fields.Selection([('not_packing', 'Belum Packing'), ('packing_done', 'Sudah Packing')], string='Packing Status') approval_invoice_date_id = fields.Many2one('approval.invoice.date', string='Approval Invoice Date') last_update_date_doc_kirim = fields.Datetime(string='Last Update Tanggal Kirim') @@ -526,7 +531,6 @@ class StockPicking(models.Model): if self.biteship_tracking_id: raise UserError(f"Order ini sudah dikirim ke Biteship. Dengan Tracking Id: {self.biteship_tracking_id}") - # Fungsi bantu: menentukan apakah kurir perlu koordinat def is_courier_need_coordinates(service_code): return service_code in [ "instant", "same_day", "instant_car", @@ -534,47 +538,42 @@ class StockPicking(models.Model): "cdd_bak", "cdd_box", "engkel_box", "engkel_bak" ] - # Ambil order line - products = self.env['sale.order.line'].search([('order_id', '=', self.sale_id.id)]) - - # Bangun data items untuk standard - def build_items_data(lines): - return [{ - "name": line.product_id.name, - "description": line.name, - "value": line.price_unit, - "quantity": line.product_uom_qty, - "weight": line.weight*1000 - } for line in lines] - - items_data_standard = build_items_data(products) + # ✅ Ambil item dari move_line_ids_with_package (qty_done > 0) + items = [] + for ml in self.move_line_ids_without_package: + if ml.qty_done <= 0: + continue - # Bangun data items untuk pengiriman instant - items_data_instant = [] - for move_line in self.move_line_ids_without_package: - order_line = self.env['sale.order.line'].search([ + product = ml.product_id + weight = product.weight or 0.1 # default minimal + line = ml.move_id.sale_line_id or self.env['sale.order.line'].search([ ('order_id', '=', self.sale_id.id), - ('product_id', '=', move_line.product_id.id) + ('product_id', '=', ml.product_id.id) ], limit=1) - if order_line: - items_data_instant.append({ - "name": order_line.product_id.name, - "description": order_line.name, - "value": order_line.price_unit, - "quantity": move_line.qty_done, - "weight": order_line.weight*1000 - }) + value = line.price_unit if line else 0 + description = line.name if line else product.name + + items.append({ + "name": product.name, + "description": description, + "value": value, + "quantity": ml.qty_done, + "weight": int(weight * 1000), + }) + + if not items: + raise UserError("Pengiriman tidak dapat dilakukan karena tidak ada barang yang divalidasi (qty_done = 0).") + + shipping_partner = self.real_shipping_id + courier_service_code = self.sale_id.delivery_service_type or "reg" - _logger.info(f"Items data standard: {items_data_standard}") - _logger.info(f"Items data instant: {items_data_instant}") - # Bangun payload dasar payload = { "origin_coordinate": { "latitude": -6.3031123, "longitude": 106.7794934999 }, - "reference_id": self.sale_id.name, + "reference_id": self.name, "shipper_contact_name": self.carrier_id.pic_name or '', "shipper_contact_phone": self.carrier_id.pic_phone or '', "shipper_organization": self.carrier_id.name, @@ -582,37 +581,27 @@ class StockPicking(models.Model): "origin_contact_phone": "081717181922", "origin_address": "Jl. Bandengan Utara Komp A & BRT. Penjaringan, Kec. Penjaringan, Jakarta (BELAKANG INDOMARET) KOTA JAKARTA UTARA PENJARINGAN", "origin_postal_code": 14440, - "destination_contact_name": self.real_shipping_id.name, - "destination_contact_phone": self.real_shipping_id.phone or self.real_shipping_id.mobile, - "destination_address": self.real_shipping_id.street, - "destination_postal_code": self.real_shipping_id.zip, + "destination_contact_name": shipping_partner.name, + "destination_contact_phone": shipping_partner.phone or shipping_partner.mobile, + "destination_address": shipping_partner.street, + "destination_postal_code": shipping_partner.zip, "origin_note": "BELAKANG INDOMARET", - "courier_type": self.sale_id.delivery_service_type or "reg", + "destination_note": f"SO: {self.sale_id.name}", + "order_note": f"SO: {self.sale_id.name}", + "courier_type": courier_service_code, "courier_company": self.carrier_id.name.lower(), "delivery_type": "now", - "items": items_data_standard + "items": items } - _logger.info(f"Delivery service type: {self.sale_id.delivery_service_type}") - _logger.info(f"Carrier: {self.carrier_id.name}") - _logger.info(f"Payload awal: {payload}") - - # Tambahkan destination_coordinate jika diperlukan - if is_courier_need_coordinates(self.sale_id.delivery_service_type): - if not self.real_shipping_id.latitude or not self.real_shipping_id.longtitude: + if is_courier_need_coordinates(courier_service_code): + if not shipping_partner.latitude or not shipping_partner.longtitude: raise UserError("Alamat tujuan tidak memiliki koordinat (latitude/longitude).") - # items_to_use = items_data_instant if items_data_instant else items_data_standard - if not items_data_instant: - raise UserError("Pengiriman instant membutuhkan produk yang sudah diproses (qty_done > 0). Harap lakukan validasi picking terlebih dahulu.") - - payload.update({ - "destination_coordinate": { - "latitude": self.real_shipping_id.latitude, - "longitude": self.real_shipping_id.longtitude, - }, - "items": items_data_instant - }) + payload["destination_coordinate"] = { + "latitude": shipping_partner.latitude, + "longitude": shipping_partner.longtitude, + } _logger.info(f"Payload untuk Biteship: {payload}") @@ -632,7 +621,7 @@ class StockPicking(models.Model): self.biteship_id = data.get("id", "") self.biteship_tracking_id = data.get("courier", {}).get("tracking_id", "") self.biteship_waybill_id = data.get("courier", {}).get("waybill_id", "") - self.delivery_tracking_no = data.get("courier", {}).get("waybill_id", "") + self.delivery_tracking_no = self.biteship_waybill_id waybill_id = self.biteship_waybill_id @@ -640,7 +629,9 @@ class StockPicking(models.Model): body=f"Biteship berhasil dilakukan.<br/>" f"Kurir: {self.carrier_id.name}<br/>" f"Tracking ID: {self.biteship_tracking_id or '-'}<br/>" - f"Resi: {waybill_id or '-'}", + f"Resi: {waybill_id or '-'}<br/>" + f"Reference: {self.name}<br/>" + f"SO: {self.sale_id.name}", message_type="comment" ) @@ -653,13 +644,11 @@ class StockPicking(models.Model): 'type': 'rainbow_man', } } - else: error_data = response.json() error_message = error_data.get("error", "Unknown error") error_code = error_data.get("code", "No code provided") raise UserError(f"Error saat mengirim ke Biteship: {error_message} (Code: {error_code})") - @api.constrains('driver_departure_date') def constrains_driver_departure_date(self): diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml index 9b16639c..b0d55104 100644 --- a/indoteknik_custom/views/stock_picking.xml +++ b/indoteknik_custom/views/stock_picking.xml @@ -91,7 +91,9 @@ /> </button> <field name="backorder_id" position="after"> + <field name="select_shipping_option_so"/> <field name="shipping_method_so_id"/> + <field name="shipping_option_so_id"/> <field name="summary_qty_detail"/> <field name="count_line_detail"/> <field name="dokumen_tanda_terima"/> |
