summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIndoteknik . <it@fixcomart.co.id>2025-08-04 09:02:28 +0700
committerIndoteknik . <it@fixcomart.co.id>2025-08-04 09:02:28 +0700
commit4aa9ca7105297079d109e20c793769476af91d02 (patch)
tree73f7067c6b868a73fb940db4cb38725d9fcd6953
parent145d15ceaf462f0b3533c441287a66410b7d12e6 (diff)
parent71c0324d483419d3b91078cf6efc2263f279362a (diff)
Merge branch 'odoo-backup' of https://bitbucket.org/altafixco/indoteknik-addons into reminder-tempo-v2
-rw-r--r--indoteknik_api/controllers/api_v1/sale_order.py106
-rw-r--r--indoteknik_api/models/sale_order.py65
-rwxr-xr-xindoteknik_custom/models/sale_order.py18
-rw-r--r--indoteknik_custom/models/stock_picking.py5
-rw-r--r--indoteknik_custom/models/tukar_guling.py2
-rw-r--r--indoteknik_custom/models/tukar_guling_po.py2
-rw-r--r--indoteknik_custom/views/purchasing_job.xml2
-rw-r--r--indoteknik_custom/views/res_partner.xml2
-rwxr-xr-xindoteknik_custom/views/sale_order.xml5
-rw-r--r--indoteknik_custom/views/user_company_request.xml3
10 files changed, 171 insertions, 39 deletions
diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py
index ccab2827..fd460ea0 100644
--- a/indoteknik_api/controllers/api_v1/sale_order.py
+++ b/indoteknik_api/controllers/api_v1/sale_order.py
@@ -1,5 +1,5 @@
from .. import controller
-from odoo import http
+from odoo import http, fields
from datetime import datetime, timedelta
from odoo.http import request
import json
@@ -103,7 +103,11 @@ class SaleOrder(controller.Controller):
'site': [],
'limit': ['default:0', 'number'],
'offset': ['default:0', 'number'],
- 'context': []
+ 'context': [],
+ 'status': [],
+ 'sort': [],
+ 'startDate': [],
+ 'endDate': [],
})
limit = params['value']['limit']
offset = params['value']['offset']
@@ -123,10 +127,19 @@ class SaleOrder(controller.Controller):
if params['value']['name']:
name = params['value']['name'].replace(' ', '%')
- domain += [
+ order_lines = request.env['sale.order.line'].search([
+ ('order_id.partner_id', 'in', partner_child_ids),
'|',
- ('name', 'ilike', '%' + name + '%'),
- ('partner_purchase_order_name', 'ilike', '%' + name + '%')
+ ('product_id.name', 'ilike', name),
+ ('product_id.default_code', 'ilike', name),
+ ])
+
+ sale_order_ids_from_lines = order_lines.mapped('order_id.id')
+
+ domain += ['|', '|',
+ ('name', 'ilike', name),
+ ('partner_purchase_order_name', 'ilike', name),
+ ('id', 'in', sale_order_ids_from_lines)
]
if params['value']['site']:
@@ -135,11 +148,86 @@ class SaleOrder(controller.Controller):
('partner_id.site_id.name', 'ilike', '%' + site + '%')
]
+ status = params['value'].get('status')
+ if status:
+ if status == 'quotation':
+ domain += [('state', '=', 'draft')]
+ domain += [('approval_status', '=', False)]
+
+ elif status == 'cancel':
+ domain += [('state', '=', 'cancel')]
+
+ elif status == 'diproses':
+ domain += [
+ ('state', '=', 'draft'),
+ ('approval_status', 'in', ['pengajuan1', 'pengajuan2']),
+ ]
+
+ elif status in ['dikemas', 'dikirim', 'selesai', 'partial']:
+ domain += [('state', '=', 'sale')]
+
+ elif status == 'all':
+ domain += []
+
+ # Sorting
+ order = None
+ if params['value']['sort']:
+ if params['value']['sort'] == 'asc':
+ order = 'amount_total asc'
+ elif params['value']['sort'] == 'desc':
+ order = 'amount_total desc'
+
+ # Filter berdasarkan tanggal order
+ try:
+ if params['value']['startDate'] and params['value']['endDate']:
+ start_date = datetime.strptime(params['value']['startDate'], '%d/%m/%Y').strftime('%Y-%m-%d 00:00:00')
+ end_date = datetime.strptime(params['value']['endDate'], '%d/%m/%Y').strftime('%Y-%m-%d 23:59:59')
+ else:
+ start_date = '2023-01-01 00:00:00'
+ end_date = fields.Datetime.now().strftime('%Y-%m-%d 23:59:59')
+
+ domain.append(('date_order', '>=', start_date))
+ domain.append(('date_order', '<=', end_date))
+
+ except ValueError:
+ return self.response(code=400, description="Invalid date format. Use 'DD/MM/YYYY'.")
+
+
+
sale_orders = request.env['sale.order'].search(
- domain, offset=offset, limit=limit)
+ domain, order=order)
+ status = params['value'].get('status')
+ if status in ['dikemas', 'dikirim', 'selesai', 'partial']:
+ filtered_orders = []
+ for sale_order in sale_orders:
+ bu_pickings = [
+ p for p in sale_order.picking_ids
+ if p.picking_type_id and p.picking_type_id.id == 29
+ ]
+ total = len(bu_pickings)
+ done_pickings = [p for p in bu_pickings if p.state == 'done']
+ done_with_driver = [p for p in done_pickings if p.driver_arrival_date]
+ done_without_driver = [p for p in done_pickings if not p.driver_arrival_date]
+
+ if status == 'dikemas' and len(done_pickings) == 0:
+ filtered_orders.append(sale_order)
+ elif status == 'dikirim' and len(done_pickings) == total and len(done_pickings) > 0 and len(done_without_driver) == total:
+ filtered_orders.append(sale_order)
+ elif status == 'selesai' and len(done_pickings) == total and len(done_pickings) > 0 and len(done_with_driver) == total:
+ filtered_orders.append(sale_order)
+ elif status == 'partial' and (
+ len(done_pickings) != total or
+ (done_with_driver and done_without_driver)
+ ):
+ filtered_orders.append(sale_order)
+ else:
+ filtered_orders = sale_orders
+
+ filtered_orders_paginated = filtered_orders[offset: offset + limit]
+
data = {
- 'sale_order_total': request.env['sale.order'].search_count(domain),
- 'sale_orders': [request.env['sale.order'].api_v1_single_response(x) for x in sale_orders]
+ 'sale_order_total': len(filtered_orders),
+ 'sale_orders': [request.env['sale.order'].api_v1_single_response(x) for x in filtered_orders_paginated]
}
return self.response(data)
@@ -149,7 +237,7 @@ class SaleOrder(controller.Controller):
def partner_get_sale_order_detail(self, **kw):
params = self.get_request_params(kw, {
'partner_id': ['number'],
- 'id': ['number']
+ 'id': ['number'],
})
if not params['valid']:
return self.response(code=400, description=params)
diff --git a/indoteknik_api/models/sale_order.py b/indoteknik_api/models/sale_order.py
index 45461974..615dcdcb 100644
--- a/indoteknik_api/models/sale_order.py
+++ b/indoteknik_api/models/sale_order.py
@@ -1,4 +1,5 @@
from odoo import models
+from datetime import datetime
class SaleOrder(models.Model):
@@ -20,12 +21,14 @@ class SaleOrder(models.Model):
'amount_untaxed': sale_order.amount_untaxed,
'amount_tax': sale_order.amount_tax,
'amount_total': sale_order.grand_total,
+ 'amount_discount': sale_order.amount_voucher_shipping_disc,
'purchase_order_name': sale_order.partner_purchase_order_name or sale_order.client_order_ref,
'purchase_order_file': True if sale_order.partner_purchase_order_file else False,
'invoice_count': sale_order.invoice_count,
'status': 'draft',
'approval_step': APPROVAL_STEP[sale_order.web_approval] if sale_order.web_approval else 0,
'date_order': self.env['rest.api'].datetime_to_str(sale_order.date_order, '%d/%m/%Y %H:%M:%S'),
+ 'payment_type': sale_order.payment_type,
'pickings': []
}
for picking in sale_order.picking_ids:
@@ -49,29 +52,32 @@ class SaleOrder(models.Model):
})
if sale_order.state == 'cancel':
data['status'] = 'cancel'
- if sale_order.state in ['draft', 'sent']:
+ if sale_order.state == 'draft' and sale_order.approval_status == False:
data['status'] = 'draft'
- if sale_order.is_continue_transaction:
- data['status'] = 'waiting'
- if sale_order.approval_status in ['pengajuan1', 'pengajuan2']:
- data['status'] = 'waiting'
- if sale_order.state == 'sale':
- data['status'] = 'sale'
- picking_count = {
- 'assigned': 0,
- 'done': 0,
- }
- for picking in sale_order.picking_ids:
- if picking.state in ['confirmed', 'assigned']:
- picking_count['assigned'] += 1
- if picking.state == 'done':
- picking_count['done'] += 1
- if picking_count['done'] > 0:
+ if sale_order.state == 'draft' and sale_order.approval_status in ['pengajuan1', 'pengajuan2']:
+ data['status'] = 'waiting'
+
+
+ if sale_order.state == 'sale':
+ bu_pickings = [
+ p for p in sale_order.picking_ids
+ if p.picking_type_id and p.picking_type_id.id == 29
+ ]
+
+ # Hitung status masing-masing picking
+ total = len(bu_pickings)
+ done_pickings = [p for p in bu_pickings if p.state == 'done']
+ done_with_driver = [p for p in done_pickings if p.driver_arrival_date]
+ done_without_driver = [p for p in done_pickings if not p.driver_arrival_date]
+
+ if len(done_pickings) == 0:
+ data['status'] = 'sale'
+ elif len(done_pickings) == total and len(done_pickings) > 0 and len(done_with_driver) == total:
+ data['status'] = 'done'
+ elif len(done_pickings) == total and len(done_pickings) > 0 and len(done_without_driver) == total:
data['status'] = 'shipping'
- if picking_count['assigned'] > 0:
- data['status'] = 'partial_shipping'
- if sale_order.state == 'done':
- data['status'] = 'done'
+ else:
+ data['status'] = 'partial_shipping'
res_users = self.env['res.users']
if context:
@@ -116,11 +122,28 @@ class SaleOrder(models.Model):
data.update(data_with_detail)
else:
data_with_detail = {
+ 'products': [],
'address': {
'customer': res_users.api_address_response(sale_order.partner_id),
}
}
data.update(data_with_detail)
+ for line in sale_order.order_line:
+ product = self.env['product.product'].api_single_response(line.product_id)
+ product['price'] = {
+ 'price': line.price_unit,
+ 'discount_percentage': line.discount,
+ 'price_discount': line.price_reduce_taxexcl,
+ 'subtotal': line.price_subtotal
+ }
+ product['quantity'] = line.product_uom_qty
+ product['available_quantity'] = line.product_available_quantity
+ for data_v2 in sale_order.fulfillment_line_v2:
+ product_v2 = self.env['product.product'].api_single_response(data_v2.product_id)
+ if product['id'] == product_v2['id']:
+ product['so_qty'] = data_v2.so_qty
+ product['reserved_stock_qty'] = data_v2.reserved_stock_qty
+ data_with_detail['products'].append(product)
return data
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index 4e36a9fb..47018f52 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -3088,6 +3088,24 @@ class SaleOrder(models.Model):
except:
pass
+ #payment term vals
+ if 'payment_term_id' in vals and any(
+ order.approval_status in ['pengajuan1', 'pengajuan2', 'approved'] for order in self):
+ raise UserError(
+ "Payment Term tidak dapat diubah karena Sales Order sedang dalam proses approval atau sudah diapprove.")
+
+ if 'payment_term_id' in vals:
+ for order in self:
+ partner = order.partner_id.parent_id or order.partner_id
+ customer_payment_term = partner.property_payment_term_id
+ if vals['payment_term_id'] != customer_payment_term.id:
+ raise UserError(
+ f"Payment Term berbeda pada Master Data Customer. "
+ f"Harap ganti ke '{customer_payment_term.name}' "
+ f"sesuai dengan payment term yang terdaftar pada customer."
+ )
+
+
res = super(SaleOrder, self).write(vals)
# Update before margin setelah write
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index 825368de..f2f5f52a 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -810,6 +810,7 @@ class StockPicking(models.Model):
self.biteship_tracking_id = data.get("courier", {}).get("tracking_id", "")
self.biteship_waybill_id = data.get("courier", {}).get("waybill_id", "")
self.delivery_tracking_no = self.biteship_waybill_id
+ self.biteship_shipping_price = data.get("price", 0.0)
waybill_id = self.biteship_waybill_id
@@ -1386,9 +1387,9 @@ class StockPicking(models.Model):
self.automatic_reserve_product()
if self.tukar_guling_id:
- self.tukar_guling_id.update_state()
+ self.tukar_guling_id.update_doc_state()
elif self.tukar_guling_po_id:
- self.tukar_guling_po_id.update_state()
+ self.tukar_guling_po_id.update_doc_state()
return res
diff --git a/indoteknik_custom/models/tukar_guling.py b/indoteknik_custom/models/tukar_guling.py
index 5411b17c..3f81393a 100644
--- a/indoteknik_custom/models/tukar_guling.py
+++ b/indoteknik_custom/models/tukar_guling.py
@@ -462,7 +462,7 @@ class TukarGuling(models.Model):
raise UserError("Submit hanya bisa dilakukan dari Draft.")
self.state = 'approval_sales'
- def update_state(self):
+ def update_doc_state(self):
# OUT tukar guling
if self.operations.picking_type_id.id == 29 and self.return_type == 'tukar_guling':
total_out = self.env['stock.picking'].search_count([
diff --git a/indoteknik_custom/models/tukar_guling_po.py b/indoteknik_custom/models/tukar_guling_po.py
index 23ca1923..92d8c9a6 100644
--- a/indoteknik_custom/models/tukar_guling_po.py
+++ b/indoteknik_custom/models/tukar_guling_po.py
@@ -419,7 +419,7 @@ class TukarGulingPO(models.Model):
else:
raise UserError("Status ini tidak bisa di-approve.")
- def update_stae(self):
+ def update_doc_state(self):
# bu input rev po
if self.operations.picking_type_id.id == 28 and self.return_type == 'revisi_po':
prt = self.env['stock.picking'].search([
diff --git a/indoteknik_custom/views/purchasing_job.xml b/indoteknik_custom/views/purchasing_job.xml
index e3866d84..2466e7be 100644
--- a/indoteknik_custom/views/purchasing_job.xml
+++ b/indoteknik_custom/views/purchasing_job.xml
@@ -17,7 +17,7 @@
<field name="status_apo" invisible="1"/>
<field name="action"/>
<field name="note"/>
- <field name="date_po"/>
+ <field name="date_po" optional="hide"/>
<field name="so_number"/>
<field name="check_pj" invisible="1"/>
<button name="action_open_job_detail"
diff --git a/indoteknik_custom/views/res_partner.xml b/indoteknik_custom/views/res_partner.xml
index 08eca7ea..b081f6f2 100644
--- a/indoteknik_custom/views/res_partner.xml
+++ b/indoteknik_custom/views/res_partner.xml
@@ -220,7 +220,7 @@
<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" />
+ <field name="payment_history_url" readonly="1" widget="url"/>
</group>
</page>
</notebook>
diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml
index e8f41ca3..868bce7b 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -355,8 +355,9 @@
</field>
<field name="payment_term_id" position="attributes">
<attribute name="attrs">
- {'readonly': [('approval_status', '=', 'approved'), ('state', 'not in',
- ['cancel', 'draft'])]}
+ {'readonly': ['|', ('approval_status', 'in', ['pengajuan1', 'pengajuan2', 'approved']),
+ ('state', 'not in',
+ ['cancel', 'draft'])]}
</attribute>
</field>
diff --git a/indoteknik_custom/views/user_company_request.xml b/indoteknik_custom/views/user_company_request.xml
index 88d04c64..5f296cb0 100644
--- a/indoteknik_custom/views/user_company_request.xml
+++ b/indoteknik_custom/views/user_company_request.xml
@@ -31,7 +31,8 @@
<group>
<field name="user_id" readonly="1"/>
<field name="similar_company_ids" invisible="1"/>
- <field name="user_company_id" domain="[('id', 'in', similar_company_ids)]"/>
+<!-- <field name="user_company_id" domain="[('id', 'in', similar_company_ids)]"/>-->
+ <field name="user_company_id" />
<field name="user_input" readonly="1"/>
<field
name="is_approve"