summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAzka Nathan <darizkyfaz@gmail.com>2025-07-14 17:03:30 +0700
committerAzka Nathan <darizkyfaz@gmail.com>2025-07-14 17:03:30 +0700
commit2eb64e50e1d41af96cf29097a5781d4df08d5f16 (patch)
tree4f7e45008821a62959585533ca20527627fdd8dc
parentee77ca5ec2947ba672c7becee3ecb583f4f25916 (diff)
parent1b70be54f939974c0232abf215f8a432b6c15244 (diff)
Merge branch 'odoo-backup' of bitbucket.org:altafixco/indoteknik-addons into odoo-backup
-rw-r--r--indoteknik_custom/models/account_move.py18
-rw-r--r--indoteknik_custom/models/commision.py5
-rwxr-xr-xindoteknik_custom/models/sale_order.py4
-rw-r--r--indoteknik_custom/models/stock_picking.py102
-rw-r--r--indoteknik_custom/views/customer_commision.xml1
-rw-r--r--indoteknik_custom/views/ir_sequence.xml2
-rw-r--r--indoteknik_custom/views/mail_template_invoice_reminder.xml8
7 files changed, 87 insertions, 53 deletions
diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py
index 5ac1c6e5..72ac5452 100644
--- a/indoteknik_custom/models/account_move.py
+++ b/indoteknik_custom/models/account_move.py
@@ -85,7 +85,7 @@ class AccountMove(models.Model):
today + timedelta(days=7),
]
- partner = self.env['res.partner'].search([('name', 'ilike', 'FLYNINDO MEGA PERSADA')], limit=1)
+ partner = self.env['res.partner'].search([('name', 'ilike', 'BANGUNAN TEKNIK GRUP')], limit=1)
if not partner:
_logger.info("Partner tidak ditemukan.")
return
@@ -149,11 +149,27 @@ class AccountMove(models.Model):
'email_to': 'andrifebriyadiputra@gmail.com', # Ubah ke partner.email untuk produksi
'email_from': 'finance@indoteknik.co.id',
'body_html': body_html,
+ 'reply_to': f'invoice+account.move_{invs[0].id}@indoteknik.co.id',
}
_logger.info(f"VALUES: {values}")
template.send_mail(invs[0].id, force_send=True, email_values=values)
+
+ # Default System User
+ user_system = self.env['res.users'].browse(25)
+ system_id = user_system.partner_id.id if user_system else False
+ _logger.info(f"System User: {user_system.name} ({user_system.id})")
+ _logger.info(f"System User ID: {system_id}")
+
+ for inv in invs:
+ inv.message_post(
+ subject=subject,
+ body=body_html,
+ subtype_id=self.env.ref('mail.mt_note').id,
+ author_id=system_id,
+ )
+
_logger.info(f"Reminder terkirim ke {partner.name} ({values['email_to']}) → {len(invs)} invoice")
diff --git a/indoteknik_custom/models/commision.py b/indoteknik_custom/models/commision.py
index 97184cdb..26b5df37 100644
--- a/indoteknik_custom/models/commision.py
+++ b/indoteknik_custom/models/commision.py
@@ -193,6 +193,7 @@ class CustomerCommision(models.Model):
commision_amt_text = fields.Char(string='Amount Text', compute='compute_delivery_amt_text')
total_cashback_text = fields.Char(string='Cashback Text', compute='compute_total_cashback_text')
total_dpp = fields.Float(string='Total DPP', compute='_compute_total_dpp')
+ biaya_lain_lain = fields.Float(string='Biaya Lain-lain')
commision_type = fields.Selection([
('fee', 'Fee'),
('cashback', 'Cashback'),
@@ -363,13 +364,13 @@ class CustomerCommision(models.Model):
else:
self.cashback = 0
self.total_commision = 0
-
+
def _compute_total_dpp(self):
for data in self:
total_dpp = 0
for line in data.commision_lines:
total_dpp = total_dpp + line.dpp
- data.total_dpp = total_dpp
+ data.total_dpp = total_dpp - data.biaya_lain_lain
@api.model
def create(self, vals):
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 6f260dfa..b9c90551 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -20,8 +20,10 @@ _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'
@@ -119,7 +121,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([
@@ -278,16 +280,22 @@ 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')
@@ -298,7 +306,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:
@@ -307,7 +315,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:
@@ -318,37 +326,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)}")
@@ -695,8 +703,9 @@ 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",
@@ -793,11 +802,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"
)
@@ -939,6 +948,9 @@ 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(
@@ -1304,7 +1316,6 @@ class StockPicking(models.Model):
)
)
-
self.validation_minus_onhand_quantity()
self.responsible = self.env.user.id
# self.send_koli_to_so()
@@ -1355,7 +1366,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([
@@ -1373,11 +1384,12 @@ 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!")
@@ -1661,7 +1673,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 = []
@@ -1676,11 +1688,12 @@ 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 '-',
@@ -1703,7 +1716,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')}"
@@ -1732,7 +1745,7 @@ class StockPicking(models.Model):
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
-
+
manifests = []
try:
@@ -1769,9 +1782,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):
@@ -1855,7 +1868,6 @@ 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 = {}
@@ -1916,7 +1928,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,
@@ -1928,7 +1940,6 @@ 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("""
@@ -1995,8 +2006,7 @@ 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)
@@ -2005,11 +2015,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'
diff --git a/indoteknik_custom/views/customer_commision.xml b/indoteknik_custom/views/customer_commision.xml
index 1c17bf63..514e6284 100644
--- a/indoteknik_custom/views/customer_commision.xml
+++ b/indoteknik_custom/views/customer_commision.xml
@@ -103,6 +103,7 @@
<field name="notification" readonly="1"/>
<!-- <field name="status" readonly="1"/>-->
<field name="payment_status" readonly="1"/>
+ <field name="biaya_lain_lain"/>
<field name="total_dpp"/>
</group>
</group>
diff --git a/indoteknik_custom/views/ir_sequence.xml b/indoteknik_custom/views/ir_sequence.xml
index d9b93ff3..f2b42c3b 100644
--- a/indoteknik_custom/views/ir_sequence.xml
+++ b/indoteknik_custom/views/ir_sequence.xml
@@ -164,7 +164,7 @@
<record id="sequence_commision_fee" model="ir.sequence">
<field name="name">Customer Commision Fee</field>
<field name="code">customer.commision.fee</field>
- <field name="prefix">FE/%(year)s/</field>
+ <field name="prefix">CC/%(year)s/</field>
<field name="padding">5</field>
<field name="number_next">1</field>
<field name="number_increment">1</field>
diff --git a/indoteknik_custom/views/mail_template_invoice_reminder.xml b/indoteknik_custom/views/mail_template_invoice_reminder.xml
index 8b3b9880..21055eb0 100644
--- a/indoteknik_custom/views/mail_template_invoice_reminder.xml
+++ b/indoteknik_custom/views/mail_template_invoice_reminder.xml
@@ -13,7 +13,7 @@
<p>Berikut adalah daftar invoice Anda yang mendekati atau telah jatuh tempo:</p>
- <table border="1" cellpadding="6" cellspacing="0" style="border-collapse: collapse; width: 100%;">
+ <table border="1" cellpadding="4" cellspacing="0" style="border-collapse: collapse; width: 100%; font-size: 12px">
<thead>
<tr style="background-color: #f2f2f2;" align="left">
<th>Invoice Number</th>
@@ -37,9 +37,11 @@
<br/>
Widya R.<br/>
Dept. Finance<br/>
- PT. INDOTEKNIK DOTCOM GEMILANG</b><br/>
+ PT. INDOTEKNIK DOTCOM GEMILANG<br/>
<img src="https://erp.indoteknik.com/api/image/ir.attachment/datas/2135765" alt="Indoteknik" style="max-width: 18%; height: auto;"></img><br/>
- +62-857-1697-0374 | finance@indoteknik.co.id</p>
+ <a href="https://wa.me/6285716970374" target="_blank">+62-857-1697-0374</a> |
+ <a href="mailto:finance@indoteknik.co.id">finance@indoteknik.co.id</a>
+ </b></p>
</div>
</field>