diff options
| author | Miqdad <ahmadmiqdad27@gmail.com> | 2025-07-14 10:49:57 +0700 |
|---|---|---|
| committer | Miqdad <ahmadmiqdad27@gmail.com> | 2025-07-14 10:49:57 +0700 |
| commit | fc0fb7fba28ad5eaf3ec1e868b54567d6f127c65 (patch) | |
| tree | b4052552d3a289ae526bd81ae00d6d4e450b1d2c | |
| parent | 5af60fda5cd584011e3f29b57ef018d7d66aee21 (diff) | |
| parent | 2af07f60a639089efc553966799b3dc225a397a2 (diff) | |
<miqdad> merge
| -rwxr-xr-x | indoteknik_custom/models/sale_order.py | 4 | ||||
| -rw-r--r-- | indoteknik_custom/models/stock_picking.py | 101 |
2 files changed, 50 insertions, 55 deletions
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 591951ca..e197a6af 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -3048,6 +3048,10 @@ class SaleOrder(models.Model): if picking.state == 'assigned': picking.carrier_id = vals['carrier_id'] + for picking in order.picking_ids: + if picking.state not in ['done', 'cancel', 'assigned']: + picking.write({'carrier_id': vals['carrier_id']}) + try: helper_ids = self._get_helper_ids() if str(self.env.user.id) in helper_ids: diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index afebb5d9..ccd42e94 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -20,10 +20,8 @@ _logger = logging.getLogger(__name__) _biteship_url = "https://api.biteship.com/v1" biteship_api_key = "biteship_live.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiaW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTc0MTE1NTU4M30.pbFCai9QJv8iWhgdosf8ScVmEeP3e5blrn33CHe7Hgo" - - # biteship_api_key = "biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTcyOTQ5ODAwMX0.L6C73couP4-cgVEfhKI2g7eMCMo3YOFSRZhS-KSuHNA" - + class StockPicking(models.Model): _inherit = 'stock.picking' @@ -121,7 +119,7 @@ class StockPicking(models.Model): waybill_id = fields.One2many(comodel_name='airway.bill', inverse_name='do_id', string='Airway Bill') purchase_representative_id = fields.Many2one('res.users', related='move_lines.purchase_line_id.order_id.user_id', string="Purchase Representative") - carrier_id = fields.Many2one('delivery.carrier', string='Shipping Method') + carrier_id = fields.Many2one('delivery.carrier', string='Shipping Method', tracking=3) shipping_status = fields.Char(string='Shipping Status', compute="_compute_shipping_status") date_reserved = fields.Datetime(string="Date Reserved", help='Tanggal ter-reserved semua barang nya', copy=False) status_printed = fields.Selection([ @@ -280,21 +278,16 @@ class StockPicking(models.Model): biteship_driver_plate_number = fields.Char('Biteship Driver Plate Number') biteship_courier_link = fields.Char('Biteship Courier Link') biteship_shipping_status = fields.Char('Biteship Shipping Status', help="Status pengiriman dari Biteship") - biteship_shipping_price = fields.Monetary('Biteship Shipping Price', currency_field='currency_id', - help="Harga pengiriman dari Biteship") + biteship_shipping_price = fields.Monetary('Biteship Shipping Price', currency_field='currency_id', help="Harga pengiriman dari Biteship") currency_id = fields.Many2one('res.currency', related='sale_id.currency_id', string='Currency', readonly=True) final_seq = fields.Float(string='Remaining Time') - shipping_method_so_id = fields.Many2one('delivery.carrier', string='Shipping Method', related='sale_id.carrier_id', - help="Shipping Method yang digunakan di SO") - shipping_option_so_id = fields.Many2one('shipping.option', string='Shipping Option', - related='sale_id.shipping_option_id', - help="Shipping Option yang digunakan di SO") + shipping_method_so_id = fields.Many2one('delivery.carrier', string='Shipping Method', related='sale_id.carrier_id', help="Shipping Method yang digunakan di SO", tracking=3) + shipping_option_so_id = fields.Many2one('shipping.option', string='Shipping Option', related='sale_id.shipping_option_id' , help="Shipping Option yang digunakan di SO", tracking=3) select_shipping_option_so = fields.Selection([ ('biteship', 'Biteship'), ('custom', 'Custom'), - ], string='Shipping Type', related='sale_id.select_shipping_option', help="Shipping Type yang digunakan di SO") - state_packing = fields.Selection([('not_packing', 'Belum Packing'), ('packing_done', 'Sudah Packing')], - string='Packing Status') + ], string='Shipping Type', related='sale_id.select_shipping_option', help="Shipping Type yang digunakan di SO", tracking=3) + 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', copy=False) update_date_doc_kirim_add = fields.Boolean(string='Update Tanggal Kirim Lewat ADD') @@ -305,7 +298,7 @@ class StockPicking(models.Model): if not self.name or not self.origin: return False return f"{self.name}" - + def _download_pod_photo(self, url): """Mengunduh foto POD dari URL""" try: @@ -314,7 +307,7 @@ class StockPicking(models.Model): return base64.b64encode(response.content) except Exception as e: raise UserError(f"Gagal mengunduh foto POD: {str(e)}") - + def _parse_datetime(self, dt_str): """Parse datetime string dari format KGX""" try: @@ -325,37 +318,37 @@ class StockPicking(models.Model): return datetime.strptime(dt_str, '%Y-%m-%dT%H:%M:%S') except ValueError: return False - + def action_get_kgx_pod(self, shipment=False): self.ensure_one() - + awb_number = shipment or self._get_kgx_awb_number() if not awb_number: raise UserError("Nomor AWB tidak dapat dibuat, pastikan picking memiliki name dan origin") - + url = "https://kgx.co.id/get_detail_awb" headers = {'Content-Type': 'application/json'} - payload = {"params": {'awb_number': awb_number}} - + payload = {"params" : {'awb_number': awb_number}} + try: response = requests.post(url, headers=headers, data=json.dumps(payload)) response.raise_for_status() data = response.json() - + if data.get('result', {}).get('data', []): pod_data = data['result']['data'][0].get('connote_pod', {}) photo_url = pod_data.get('photo') - + self.kgx_pod_photo_url = photo_url self.kgx_pod_signature = pod_data.get('signature') self.kgx_pod_receiver = pod_data.get('receiver') self.kgx_pod_receive_time = self._parse_datetime(pod_data.get('timeReceive')) self.driver_arrival_date = self._parse_datetime(pod_data.get('timeReceive')) - + return data else: raise UserError(f"Tidak ditemukan data untuk AWB: {awb_number}") - + except requests.exceptions.RequestException as e: raise UserError(f"Gagal mengambil data POD: {str(e)}") @@ -702,9 +695,8 @@ class StockPicking(models.Model): raise UserError(f"Order ini sudah dikirim ke Biteship. Dengan Tracking Id: {self.biteship_tracking_id}") if self.sale_id.select_shipping_option == 'custom': - raise UserError( - "Shipping Option pada Sales Order ini adalah *Custom*. Tidak dapat dikirim melalui Biteship.") - + raise UserError("Shipping Option pada Sales Order ini adalah *Custom*. Tidak dapat dikirim melalui Biteship.") + def is_courier_need_coordinates(service_code): return service_code in [ "instant", "same_day", "instant_car", @@ -801,11 +793,11 @@ class StockPicking(models.Model): self.message_post( 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 '-'}<br/>" - f"Reference: {self.name}<br/>" - f"SO: {self.sale_id.name}", + f"Kurir: {self.carrier_id.name}<br/>" + f"Tracking ID: {self.biteship_tracking_id or '-'}<br/>" + f"Resi: {waybill_id or '-'}<br/>" + f"Reference: {self.name}<br/>" + f"SO: {self.sale_id.name}", message_type="comment" ) @@ -947,9 +939,6 @@ class StockPicking(models.Model): pending_section = None # Invoice values. invoice_vals = order._prepare_invoice() - invoice_date = self.date_done - invoice_vals['date'] = invoice_date - invoice_vals['invoice_date'] = invoice_date # Invoice line values (keep only necessary sections). for line in self.move_ids_without_package: po_line = self.env['purchase.order.line'].search( @@ -1315,6 +1304,7 @@ class StockPicking(models.Model): ) ) + self.validation_minus_onhand_quantity() self.responsible = self.env.user.id # self.send_koli_to_so() @@ -1365,7 +1355,7 @@ class StockPicking(models.Model): if 'BU/PUT' in self.name: self.automatic_reserve_product() return res - + def automatic_reserve_product(self): if self.state == 'done': po = self.env['purchase.order'].search([ @@ -1383,12 +1373,11 @@ class StockPicking(models.Model): continue invoice = self.env['account.move'].search( - [('sale_id', '=', picking.sale_id.id), ('state', 'not in', ['draft', 'cancel']), - ('move_type', '=', 'out_invoice')], limit=1) + [('sale_id', '=', picking.sale_id.id), ('state', 'not in', ['draft', 'cancel']), ('move_type', '=', 'out_invoice')], limit=1) if not invoice: continue - + if not picking.so_lama and invoice and (not picking.date_doc_kirim or not invoice.invoice_date): raise UserError("Tanggal Kirim atau Tanggal Invoice belum diisi!") @@ -1672,7 +1661,7 @@ class StockPicking(models.Model): self.ensure_one() order = self.env['sale.order'].search([('name', '=', self.sale_id.name)], limit=1) - + sale_order_delay = self.env['sale.order.delay'].search([('so_number', '=', order.name)], limit=1) product_shipped = [] @@ -1687,12 +1676,11 @@ class StockPicking(models.Model): 'delivery_order': { 'name': self.name, 'carrier': self.carrier_id.name or '-', - 'service': order.delivery_service_type or '-', + 'service' : order.delivery_service_type or '-', 'receiver_name': '', 'receiver_city': '' }, - 'delivered_date': self.driver_departure_date.strftime( - '%d %b %Y') if self.driver_departure_date != False else '-', + 'delivered_date': self.driver_departure_date.strftime('%d %b %Y') if self.driver_departure_date != False else '-', 'delivered': False, 'status': self.shipping_status, 'waybill_number': self.delivery_tracking_no or '-', @@ -1715,7 +1703,7 @@ class StockPicking(models.Model): elif sale_order_delay.status == 'early': day_start = day_start - sale_order_delay.days_delayed day_end = day_end - sale_order_delay.days_delayed - + eta_start = order.date_order + timedelta(days=day_start) eta_end = order.date_order + timedelta(days=day_end) formatted_eta = f"{eta_start.strftime('%d %b')} - {eta_end.strftime('%d %b %Y')}" @@ -1744,7 +1732,7 @@ class StockPicking(models.Model): "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } - + manifests = [] try: @@ -1781,9 +1769,9 @@ class StockPicking(models.Model): "manifests": [], "delivered": False } - except Exception as e: + except Exception as e : _logger.error(f"Error fetching Biteship order for picking {self.id}: {str(e)}") - return {'error': str(e)} + return { 'error': str(e) } # ACTION GET TRACKING MANUAL BITESHIP # def action_sync_biteship_tracking(self): @@ -1867,6 +1855,7 @@ class StockPicking(models.Model): return description_map.get(status, f"Status '{status}' diterima dari Biteship") + def log_biteship_event_from_webhook(self, status, timestamp, description, extra_data=None): self.ensure_one() updated_fields = {} @@ -1927,7 +1916,7 @@ class StockPicking(models.Model): # Hindari log duplikat if not self._has_existing_log(log_line): - biteship_user = self.env['res.users'].sudo().browse(15710) # ID live + biteship_user = self.env['res.users'].sudo().browse(15710) # ID live # biteship_user = self.env['res.users'].sudo().browse(15710) # ID user (cek di db) self.sudo().message_post( body=log_line, @@ -1939,6 +1928,7 @@ class StockPicking(models.Model): self.write(updated_fields) _logger.info(f"[Webhook] Updated fields on picking {self.name}: {updated_fields}") + def _has_existing_log(self, log_line): self.ensure_one() self.env.cr.execute(""" @@ -2005,7 +1995,8 @@ class StockPicking(models.Model): days_end = self.sale_id.estimated_arrival_days or (self.sale_id.estimated_arrival_days + 3) start_date = self.sale_id.create_date + datetime.timedelta(days=days_start) end_date = self.sale_id.create_date + datetime.timedelta(days=days_end) - + + add_day_start = 0 add_day_end = 0 sale_order_delay = self.env['sale.order.delay'].search([('so_number', '=', self.sale_id.name)], limit=1) @@ -2014,11 +2005,11 @@ class StockPicking(models.Model): add_day_start = sale_order_delay.days_delayed add_day_end = sale_order_delay.days_delayed elif sale_order_delay.status == 'early': - add_day_start = -abs(sale_order_delay.days_delayed) - add_day_end = -abs(sale_order_delay.days_delayed) - - fastest_eta = start_date + datetime.timedelta(days=add_day_start + add_day_start) - + add_day_start = -abs(sale_order_delay.days_delayed) + add_day_end = -abs(sale_order_delay.days_delayed) + + fastest_eta = start_date +datetime.timedelta(days=add_day_start + add_day_start) + longest_eta = end_date + datetime.timedelta(days=add_day_end) format_time = '%d %b %Y' |
