summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAzka Nathan <darizkyfaz@gmail.com>2025-07-04 09:24:17 +0700
committerAzka Nathan <darizkyfaz@gmail.com>2025-07-04 09:24:17 +0700
commit41ccfddeb5c62ad626d4457bf5b60dc4bfdcd9d7 (patch)
treee92ca22db753b0dd8e3679badb2c862b2d8623aa
parent38ba3d7f5b59a4444d9eb953a6c83e4ab6015ba6 (diff)
parentdb60e29b2f599ac21e96ffdfb5be94e3c0ba6a2f (diff)
Merge branch 'odoo-backup' of bitbucket.org:altafixco/indoteknik-addons into odoo-backup
-rwxr-xr-xindoteknik_custom/models/purchase_order.py60
-rwxr-xr-xindoteknik_custom/models/sale_order.py153
-rw-r--r--indoteknik_custom/views/res_partner.xml11
3 files changed, 156 insertions, 68 deletions
diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py
index a3941b3b..4dc26d74 100755
--- a/indoteknik_custom/models/purchase_order.py
+++ b/indoteknik_custom/models/purchase_order.py
@@ -101,43 +101,65 @@ class PurchaseOrder(models.Model):
@api.depends('name')
def _compute_bu_related_count(self):
+ StockPicking = self.env['stock.picking']
for order in self:
if not order.name:
order.bu_related_count = 0
continue
- # BU langsung dari PO
- base_bu = self.env['stock.picking'].search([
+ # Ambil semua BU awal dari PO
+ base_bu = StockPicking.search([
('name', 'ilike', 'BU/'),
('origin', 'ilike', order.name)
])
- base_names = base_bu.mapped('name')
- # Return dari BU di atas
- return_bu = self.env['stock.picking'].search([
- ('origin', 'in', [f"Return of {name}" for name in base_names])
- ])
+ all_bu = base_bu
+ seen_names = set(base_bu.mapped('name'))
+
+ # Loop rekursif untuk mencari seluruh return BU
+ while True:
+ next_bu = StockPicking.search([
+ ('name', 'ilike', 'BU/'),
+ ('origin', 'in', ['Return of %s' % name for name in seen_names])
+ ])
+ next_names = set(next_bu.mapped('name'))
+
+ if not next_names - seen_names:
+ break
+
+ all_bu |= next_bu
+ seen_names |= next_names
+
+ order.bu_related_count = len(all_bu)
- order.bu_related_count = len(base_bu) + len(return_bu)
def action_view_related_bu(self):
self.ensure_one()
+ StockPicking = self.env['stock.picking']
+
# Step 1: cari semua BU pertama (PUT, INT) yang berasal dari PO ini
- base_bu = self.env['stock.picking'].search([
+ base_bu = StockPicking.search([
('name', 'ilike', 'BU/'),
('origin', 'ilike', self.name)
])
- base_bu_names = base_bu.mapped('name')
- # Step 2: cari BU turunan (seperti BU/VRT) yang origin-nya mengandung nama BU tersebut
- domain = [
- '|',
- '&',
- ('name', 'ilike', 'BU/'),
- ('origin', 'ilike', self.name),
- ('origin', 'in', [f"Return of {name}" for name in base_bu_names])
- ]
+ all_bu = base_bu
+ seen_names = set(base_bu.mapped('name'))
+
+ # Step 2: Loop rekursif cari BU dengan origin 'Return of {name}'
+ while True:
+ next_bu = StockPicking.search([
+ ('name', 'ilike', 'BU/'),
+ ('origin', 'in', ['Return of %s' % name for name in seen_names])
+ ])
+ next_names = set(next_bu.mapped('name'))
+
+ if not next_names - seen_names:
+ break
+
+ all_bu |= next_bu
+ seen_names |= next_names
return {
'name': 'Related BU (INT/PRT/PUT/VRT)',
@@ -145,7 +167,7 @@ class PurchaseOrder(models.Model):
'res_model': 'stock.picking',
'view_mode': 'tree,form',
'target': 'current',
- 'domain': domain,
+ 'domain': [('id', 'in', list(all_bu.ids))],
}
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index 109771e9..591951ca 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -388,7 +388,9 @@ class SaleOrder(models.Model):
pickings = order.picking_ids.filtered(
lambda p: p.state in ('assigned', 'done') and p.date_reserved and 'BU/PICK/' in (p.name or '')
)
- order.eta_date_reserved = min(pickings.mapped('date_done')) if pickings else False
+ done_dates = [d for d in pickings.mapped('date_done') if d]
+ order.eta_date_reserved = min(done_dates) if done_dates else False
+ # order.eta_date_reserved = min(pickings.mapped('date_done')) if pickings else False
@api.onchange('shipping_cost_covered')
def _onchange_shipping_cost_covered(self):
@@ -845,25 +847,36 @@ class SaleOrder(models.Model):
if total_weight == 0:
raise UserError("Tidak dapat mengestimasi ongkir tanpa berat yang valid.")
- destination_subsdistrict_id = self.real_shipping_id.kecamatan_id.rajaongkir_id
+ kecamatan_name = self.real_shipping_id.kecamatan_id.name
+ kota_name = self.real_shipping_id.kota_id.name
+ kelurahan_name = self.real_shipping_id.kelurahan_id.name
+
+ destination_subsdistrict_id = self._get_subdistrict_id_from_komerce(kecamatan_name, kota_name, kelurahan_name)
+
+ # destination_subsdistrict_id = self.real_shipping_id.kecamatan_id.rajaongkir_id
if not destination_subsdistrict_id:
raise UserError("Gagal mendapatkan ID kota tujuan.")
result = self._call_rajaongkir_api(total_weight, destination_subsdistrict_id)
+ if not result or not result.get('data'):
+ raise UserError(_("Kurir %s tidak tersedia untuk tujuan ini. Silakan pilih kurir lain.") % self.carrier_id.name)
+
if result:
shipping_options = []
- for courier in result['rajaongkir']['results']:
- for cost_detail in courier['costs']:
- service = cost_detail['service']
- description = cost_detail['description']
- etd = cost_detail['cost'][0]['etd']
- value = cost_detail['cost'][0]['value']
- shipping_options.append((service, description, etd, value, courier['code']))
-
+
+ for cost in result.get('data', []):
+ service = cost.get('service')
+ description = cost.get('description')
+ etd = cost.get('etd', '')
+ value = cost.get('cost', 0)
+ provider = cost.get('code')
+
+ shipping_options.append((service, description, etd, value, provider))
+
self.env["shipping.option"].search([('sale_order_id', '=', self.id)]).unlink()
_logger.info(f"Shipping options: {shipping_options}")
-
+
for service, description, etd, value, provider in shipping_options:
self.env["shipping.option"].create({
"name": service,
@@ -873,19 +886,15 @@ class SaleOrder(models.Model):
"sale_order_id": self.id,
})
-
self.shipping_option_id = self.env["shipping.option"].search([('sale_order_id', '=', self.id)], limit=1).id
_logger.info(f"Shipping option SO ID: {self.shipping_option_id}")
self.message_post(
body=f"Estimasi Ongkos Kirim: Rp{self.delivery_amt}<br/>Detail Lain:<br/>"
- f"{'<br/>'.join([f'Service: {s[0]}, Description: {s[1]}, ETD: {s[2]} hari, Cost: Rp {s[3]}' for s in shipping_options])}",
+ f"{'<br/>'.join([f'Service: {s[0]}, Description: {s[1]}, ETD: {s[2]}, Cost: Rp {s[3]}' for s in shipping_options])}",
message_type="comment"
)
-
- # self.message_post(body=f"Estimasi Ongkos Kirim: Rp{self.delivery_amt}<br/>Detail Lain:<br/>{'<br/>'.join([f'Service: {s[0]}, Description: {s[1]}, ETD: {s[2]} hari, Cost: Rp {s[3]}' for s in shipping_options])}", message_type="comment")
-
else:
raise UserError("Gagal mendapatkan estimasi ongkir.")
@@ -1191,25 +1200,30 @@ class SaleOrder(models.Model):
def _call_rajaongkir_api(self, total_weight, destination_subsdistrict_id):
- url = 'https://pro.rajaongkir.com/api/cost'
+ url = 'https://rajaongkir.komerce.id/api/v1/calculate/domestic-cost'
headers = {
'key': '9b1310f644056d84d60b0af6bb21611a',
}
courier = self.carrier_id.name.lower()
data = {
- 'origin': 2127,
- 'originType': 'subdistrict',
+ 'origin': 17656,
+ # 'originType': 'subdistrict',
'destination': int(destination_subsdistrict_id),
- 'destinationType': 'subdistrict',
+ # 'destinationType': 'subdistrict',
'weight': int(total_weight * 1000),
'courier': courier,
}
- response = requests.post(url, headers=headers, data=data)
- if response.status_code == 200:
- return response.json()
- return None
+ try:
+ _logger.info(f"Calling RajaOngkir API with data: {data}")
+ response = requests.post(url, headers=headers, data=data)
+ _logger.info(f"RajaOngkir response: {response.status_code} - {response.text}")
+
+ if response.status_code == 200:
+ return response.json()
+ except Exception as e:
+ _logger.error(f"Exception while calling RajaOngkir: {str(e)}")
def _normalize_city_name(self, city_name):
city_name = city_name.lower()
@@ -1223,37 +1237,82 @@ class SaleOrder(models.Model):
return city_name
- def _get_city_id_by_name(self, city_name):
- url = 'https://pro.rajaongkir.com/api/city'
+ # def _get_city_id_by_name(self, city_name):
+ # url = 'https://pro.rajaongkir.com/api/city'
+ # headers = {
+ # 'key': '9b1310f644056d84d60b0af6bb21611a',
+ # }
+
+ # normalized_city_name = self._normalize_city_name(city_name)
+
+ # response = requests.get(url, headers=headers)
+ # if response.status_code == 200:
+ # city_data = response.json()
+ # for city in city_data['rajaongkir']['results']:
+ # if city['city_name'].lower() == normalized_city_name:
+ # return city['city_id']
+ # return None
+
+ # def _get_subdistrict_id_by_name(self, city_id, subdistrict_name):
+ # url = f'https://pro.rajaongkir.com/api/subdistrict?city={city_id}'
+ # headers = {
+ # 'key': '9b1310f644056d84d60b0af6bb21611a',
+ # }
+
+ # response = requests.get(url, headers=headers)
+ # if response.status_code == 200:
+ # subdistrict_data = response.json()
+ # for subdistrict in subdistrict_data['rajaongkir']['results']:
+ # subsdistrict_1 = subdistrict['subdistrict_name'].lower()
+ # subsdistrict_2 = subdistrict_name.lower()
+
+ # if subsdistrict_1 == subsdistrict_2:
+ # return subdistrict['subdistrict_id']
+ # return None
+
+ def _get_subdistrict_id_from_komerce(self, kecamatan_name, kota_name, kelurahan_name=None):
+ url = 'https://rajaongkir.komerce.id/api/v1/destination/domestic-destination'
headers = {
'key': '9b1310f644056d84d60b0af6bb21611a',
}
- normalized_city_name = self._normalize_city_name(city_name)
-
- response = requests.get(url, headers=headers)
- if response.status_code == 200:
- city_data = response.json()
- for city in city_data['rajaongkir']['results']:
- if city['city_name'].lower() == normalized_city_name:
- return city['city_id']
- return None
+ if kelurahan_name:
+ search = f"{kelurahan_name} {kecamatan_name} {kota_name}"
+ else:
+ search = f"{kecamatan_name} {kota_name}"
- def _get_subdistrict_id_by_name(self, city_id, subdistrict_name):
- url = f'https://pro.rajaongkir.com/api/subdistrict?city={city_id}'
- headers = {
- 'key': '9b1310f644056d84d60b0af6bb21611a',
+ params = {
+ 'search': search,
+ 'limit': 5
}
- response = requests.get(url, headers=headers)
- if response.status_code == 200:
- subdistrict_data = response.json()
- for subdistrict in subdistrict_data['rajaongkir']['results']:
- subsdistrict_1 = subdistrict['subdistrict_name'].lower()
- subsdistrict_2 = subdistrict_name.lower()
+ try:
+ response = requests.get(url, headers=headers, params=params, timeout=10)
+ if response.status_code == 200:
+ data = response.json().get('data', [])
+ _logger.info(f"[Komerce] Fetched {len(data)} subdistricts for search '{search}'")
+ _logger.info(f"[Komerce] Response: {data}")
+
+ normalized_kota = self._normalize_city_name(kota_name)
+
+ for item in data:
+ match_kelurahan = (
+ not kelurahan_name or
+ item.get('subdistrict_name', '').lower() == kelurahan_name.lower()
+ )
+ if (
+ match_kelurahan and
+ item.get('district_name', '').lower() == kecamatan_name.lower() and
+ item.get('city_name', '').lower() == normalized_kota
+ ):
+ return item.get('id')
+
+ _logger.warning(f"[Komerce] No match for '{kecamatan_name}' in city '{kota_name}' with kelurahan '{kelurahan_name}'")
+ else:
+ _logger.error(f"[Komerce] HTTP Error {response.status_code}: {response.text}")
+ except Exception as e:
+ _logger.error(f"[Komerce] Exception: {e}")
- if subsdistrict_1 == subsdistrict_2:
- return subdistrict['subdistrict_id']
return None
def _compute_type_promotion(self):
diff --git a/indoteknik_custom/views/res_partner.xml b/indoteknik_custom/views/res_partner.xml
index 6115587b..ac4d0364 100644
--- a/indoteknik_custom/views/res_partner.xml
+++ b/indoteknik_custom/views/res_partner.xml
@@ -108,6 +108,13 @@
<xpath expr="//field[@name='property_supplier_payment_term_id']" position="attributes">
<attribute name="readonly">1</attribute>
</xpath>
+ <xpath expr="//notebook/page[@name='accounting']" position="inside">
+ <group string="Aging Info">
+ <field name="avg_aging" readonly="1"/>
+ <field name="payment_difficulty" attrs="{'readonly': [('parent_id', '!=', False)]}" />
+ <field name="payment_history_url" readonly="1" />
+ </group>
+ </xpath>
<notebook>
<page string="Pengajuan Tempo">
<!-- Informasi Usaha Section -->
@@ -181,11 +188,11 @@
<field name="dokumen_pengiriman_input"/>
<field name="dokumen_invoice"/>
</group>
- <group string="Aging Info">
+ <!-- <group string="Aging Info">
<field name="avg_aging" readonly="1"/>
<field name="payment_difficulty" attrs="{'readonly': [('parent_id', '!=', False)]}" />
<field name="payment_history_url" readonly="1" />
- </group>
+ </group> -->
</group>
<!-- Supplier Lines Section -->