summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortrisusilo48 <tri.susilo@altama.co.id>2025-03-19 10:23:27 +0700
committertrisusilo48 <tri.susilo@altama.co.id>2025-03-19 10:23:27 +0700
commite0ba42d70cda5ab419badac0775b550e63645b3b (patch)
treed58923caf57b341a3c3c97f1fa08278e641788a8
parentfc5defa647bcdd317dc2d4069432c2dcc1141344 (diff)
parent9e293f201e3c43662c3866fa06eaa36805d69cc5 (diff)
Merge branch 'odoo-backup' into feature/feedback_bitehisp
# Conflicts: # indoteknik_custom/models/sale_order.py
-rw-r--r--indoteknik_api/controllers/api_v1/partner.py2
-rw-r--r--indoteknik_api/controllers/api_v1/user.py20
-rw-r--r--indoteknik_custom/models/commision.py15
-rw-r--r--indoteknik_custom/models/invoice_reklas.py6
-rwxr-xr-xindoteknik_custom/models/sale_order.py80
-rw-r--r--indoteknik_custom/models/stock_picking.py45
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv1
-rw-r--r--indoteknik_custom/views/customer_commision.xml4
-rwxr-xr-xindoteknik_custom/views/sale_order.xml1
-rw-r--r--indoteknik_custom/views/stock_picking.xml16
10 files changed, 163 insertions, 27 deletions
diff --git a/indoteknik_api/controllers/api_v1/partner.py b/indoteknik_api/controllers/api_v1/partner.py
index ebd91210..126fded4 100644
--- a/indoteknik_api/controllers/api_v1/partner.py
+++ b/indoteknik_api/controllers/api_v1/partner.py
@@ -78,7 +78,7 @@ class Partner(controller.Controller):
'district_id': ['number', 'alias:kecamatan_id'],
'sub_district_id': ['number', 'alias:kelurahan_id', 'exclude_if_null'],
'zip': ['required'],
- 'longitude': '', # Perbaikan dari longtitude ke longitude
+ 'longtitude': '',
'latitude': '',
'address_map': [],
'alamat_lengkap_text': []
diff --git a/indoteknik_api/controllers/api_v1/user.py b/indoteknik_api/controllers/api_v1/user.py
index c0974367..b5b7e055 100644
--- a/indoteknik_api/controllers/api_v1/user.py
+++ b/indoteknik_api/controllers/api_v1/user.py
@@ -131,6 +131,7 @@ class User(controller.Controller):
nama_wajib_pajak = kw.get('nama_wajib_pajak', False)
is_pkp = kw.get('is_pkp')
is_terdaftar = kw.get('is_terdaftar', False)
+ is_terdaftar = False if is_terdaftar == 'false' else is_terdaftar
type_acc = kw.get('type_acc', 'individu') or 'individu'
if not name or not email or not password:
@@ -162,9 +163,7 @@ class User(controller.Controller):
'sel_groups_1_9_10': 9
}
- user = request.env['res.users'].create(user_data)
- user.partner_id.email = email
- user.partner_id.mobile = phone
+
if type_acc == 'business' and business_name:
# Eksekusi query SQL menggunakan Levenshtein distance
@@ -182,7 +181,9 @@ class User(controller.Controller):
if result and is_terdaftar:
match_company_name = result[2]
match_company_id = result[0]
-
+ user = request.env['res.users'].create(user_data)
+ user.partner_id.email = email
+ user.partner_id.mobile = phone
# Create a user company request
request.env['user.company.request'].create({
'user_id': user.partner_id.id,
@@ -190,6 +191,9 @@ class User(controller.Controller):
'user_input': business_name
})
else:
+ if not result and is_terdaftar:
+ response['reason'] = 'BISNIS_NOT_FOUND'
+ return self.response(response)
if not nama_wajib_pajak and is_pkp == 'false':
nama_wajib_pajak = business_name
@@ -213,6 +217,10 @@ class User(controller.Controller):
'property_account_payable_id': 438,
'active': False,
}
+
+ user = request.env['res.users'].create(user_data)
+ user.partner_id.email = email
+ user.partner_id.mobile = phone
new_company = request.env['res.partner'].create(new_company_data)
request.env['user.company.request'].create({
'user_id': user.partner_id.id,
@@ -247,8 +255,10 @@ class User(controller.Controller):
'mimetype': sppkp_mimetype
})
new_company.message_post(body="SPPKP Uploaded", attachment_ids=[sppkp_attachment.id])
-
if type_acc == 'individu':
+ user = request.env['res.users'].create(user_data)
+ user.partner_id.email = email
+ user.partner_id.mobile = phone
user.partner_id.customer_type = 'nonpkp'
user.partner_id.npwp = '00.000.000.0-000.000'
user.partner_id.sppkp = '-'
diff --git a/indoteknik_custom/models/commision.py b/indoteknik_custom/models/commision.py
index 6920154a..0d31e954 100644
--- a/indoteknik_custom/models/commision.py
+++ b/indoteknik_custom/models/commision.py
@@ -157,7 +157,22 @@ class CustomerCommision(models.Model):
('pending', 'Pending'),
('payment', 'Payment'),
], string='Payment Status', copy=False, readonly=True, tracking=3, default='pending')
+ grouped_so_number = fields.Char(string='Group SO Number', compute='_compute_grouped_numbers')
+ grouped_invoice_number = fields.Char(string='Group Invoice Number', compute='_compute_grouped_numbers')
+ def _compute_grouped_numbers(self):
+ for rec in self:
+ so_numbers = set()
+ invoice_numbers = set()
+
+ for line in rec.commision_lines:
+ if line.invoice_id:
+ if line.invoice_id.sale_id:
+ so_numbers.add(line.invoice_id.sale_id.name)
+ invoice_numbers.add(line.invoice_id.name)
+
+ rec.grouped_so_number = ', '.join(sorted(so_numbers))
+ rec.grouped_invoice_number = ', '.join(sorted(invoice_numbers))
# add status for type of commision, fee, rebate / cashback
# include child or not?
diff --git a/indoteknik_custom/models/invoice_reklas.py b/indoteknik_custom/models/invoice_reklas.py
index f5bb5a25..d10d4c31 100644
--- a/indoteknik_custom/models/invoice_reklas.py
+++ b/indoteknik_custom/models/invoice_reklas.py
@@ -18,6 +18,12 @@ class InvoiceReklas(models.TransientModel):
('pembelian', 'Pembelian'),
], string='Reklas Tipe')
+ @api.onchange('reklas_type')
+ def _onchange_reklas_type(self):
+ if self.reklas_type == 'penjualan':
+ invoices = self.env['account.move'].browse(self._context.get('active_ids', []))
+ self.pay_amt = invoices.amount_total
+
def create_reklas(self):
if not self.reklas_type:
raise UserError('Reklas Tipe harus diisi')
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index e2755eba..acad7729 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -1,3 +1,5 @@
+from re import search
+
from odoo import fields, models, api, _
from odoo.exceptions import UserError, ValidationError
from datetime import datetime, timedelta
@@ -51,6 +53,16 @@ class CancelReasonOrder(models.TransientModel):
order.confirm_cancel_order()
return {'type': 'ir.actions.act_window_close'}
+
+class ShippingOption(models.Model):
+ _name = "shipping.option"
+ _description = "Shipping Option"
+
+ name = fields.Char(string="Option Name", required=True)
+ price = fields.Float(string="Price", required=True)
+ provider = fields.Char(string="Provider")
+ etd = fields.Char(string="Estimated Delivery Time")
+ sale_order_id = fields.Many2one('sale.order', string="Sale Order", ondelete="cascade")
class SaleOrder(models.Model):
_inherit = "sale.order"
@@ -196,8 +208,7 @@ class SaleOrder(models.Model):
# )
expected_ready_to_ship = fields.Datetime(
string='ET Ready to Ship',
- copy=False,
- store=True
+ copy=False
)
shipping_method_picking = fields.Char(string='Shipping Method Picking', compute='_compute_shipping_method_picking')
@@ -221,6 +232,12 @@ class SaleOrder(models.Model):
string="Attachment Bukti Cancel", readonly=False,
)
nomor_so_pengganti = fields.Char(string='Nomor SO Pengganti', copy=False, tracking=3)
+ shipping_option_id = fields.Many2one("shipping.option", string="Selected Shipping Option", domain="['|', ('sale_order_id', '=', False), ('sale_order_id', '=', id)]")
+
+ @api.constrains('shipping_option_id')
+ def _check_shipping_option(self):
+ for rec in self:
+ rec.delivery_amt = rec.shipping_option_id.price
def _compute_shipping_method_picking(self):
for order in self:
@@ -268,15 +285,26 @@ class SaleOrder(models.Model):
if total_weight == 0:
raise UserError("Tidak dapat mengestimasi ongkir tanpa berat yang valid.")
-
+
if total_weight < 10:
total_weight = 10
+
self.delivery_amt = total_weight * 3000
+
+ shipping_option = self.env["shipping.option"].create({
+ "name": "Indoteknik Delivery",
+ "price": self.delivery_amt,
+ "provider": "Indoteknik",
+ "etd": "1-2 Hari",
+ "sale_order_id": self.id,
+ })
+ self.shipping_option_id = shipping_option.id
def action_estimate_shipping(self):
if self.carrier_id.id in [1, 151]:
self.action_indoteknik_estimate_shipping()
return
+
total_weight = 0
missing_weight_products = []
@@ -294,33 +322,35 @@ class SaleOrder(models.Model):
if total_weight == 0:
raise UserError("Tidak dapat mengestimasi ongkir tanpa berat yang valid.")
- # Mendapatkan city_id berdasarkan nama kota
- origin_city_name = self.warehouse_id.partner_id.kota_id.name
destination_subsdistrict_id = self.real_shipping_id.kecamatan_id.rajaongkir_id
-
if not destination_subsdistrict_id:
- raise UserError("Gagal mendapatkan ID kota asal atau tujuan.")
+ raise UserError("Gagal mendapatkan ID kota tujuan.")
result = self._call_rajaongkir_api(total_weight, destination_subsdistrict_id)
if result:
- estimated_cost = result['rajaongkir']['results'][0]['costs'][0]['cost'][0]['value']
- self.delivery_amt = estimated_cost
-
- shipping_info = []
+ 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_info.append(f"Service: {service}, Description: {description}, ETD: {etd} hari, Cost: Rp {value}")
+ shipping_options.append((service, description, etd, value, courier['code']))
+
+ self.env["shipping.option"].search([('sale_order_id', '=', self.id)]).unlink()
- log_message = "<br/>".join(shipping_info)
+ for service, description, etd, value, provider in shipping_options:
+ self.env["shipping.option"].create({
+ "name": service,
+ "price": value,
+ "provider": provider,
+ "etd": etd,
+ "sale_order_id": self.id,
+ })
+
+ self.shipping_option_id = self.env["shipping.option"].search([('sale_order_id', '=', self.id)], limit=1).id
- description_ongkir = result['rajaongkir']['results'][0]['costs'][0]['description']
- etd_ongkir = result['rajaongkir']['results'][0]['costs'][0]['cost'][0]['etd']
- service_ongkir = result['rajaongkir']['results'][0]['costs'][0]['service']
- self.message_post(body=f"Estimasi Ongkos Kirim: Rp{self.delivery_amt}<br/>Service: {service_ongkir}<br/>Description: {description_ongkir}<br/>ETD: {etd_ongkir}<br/>Detail Lain:<br/>{log_message}")
+ 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])}")
else:
raise UserError("Gagal mendapatkan estimasi ongkir.")
@@ -948,8 +978,20 @@ class SaleOrder(models.Model):
raise UserError("Customer Reference kosong, di isi dengan NO PO jika PO tidak ada mohon ditulis Tanpa PO")
if not order.user_id.active:
raise UserError("Salesperson sudah tidak aktif, mohon diisi yang benar pada data SO dan Contact")
-
+
+ def check_product_bom(self):
+ for order in self:
+ for line in order.order_line:
+ if 'bom-it' in line.name.lower() or 'bom' in line.product_id.default_code.lower() if line.product_id.default_code else False:
+ search_bom = self.env['mrp.production'].search([('product_id', '=', line.product_id.id)],order='name desc')
+ if search_bom:
+ confirmed_bom = search_bom.filtered(lambda x: x.state == 'confirmed')
+ if not confirmed_bom:
+ raise UserError("Product BOM belum dikonfirmasi di Manufacturing Orders. Silakan hubungi MD.")
+ else:
+ raise UserError("Product BOM tidak di temukan di manufacturing orders, silahkan hubungi MD")
def sale_order_approve(self):
+ self.check_product_bom()
self.check_credit_limit()
self.check_limit_so_to_invoice()
if self.validate_different_vendor() and not self.vendor_approval:
@@ -1009,6 +1051,7 @@ class SaleOrder(models.Model):
order.approval_status = 'pengajuan2'
return self._create_approval_notification('Pimpinan')
elif order._requires_approval_margin_manager():
+ self.check_product_bom()
self.check_credit_limit()
self.check_limit_so_to_invoice()
order.approval_status = 'pengajuan1'
@@ -1188,6 +1231,7 @@ class SaleOrder(models.Model):
def action_confirm(self):
for order in self:
+ order.check_product_bom()
order.check_credit_limit()
order.check_limit_so_to_invoice()
if self.validate_different_vendor() and not self.vendor_approval:
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index edc9cc78..9e5fca66 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -131,6 +131,16 @@ class StockPicking(models.Model):
('cancel', 'Cancelled'),
], string='Status Reserve', tracking=True, copy=False, help="The current state of the stock picking.")
notee = fields.Text(string="Note")
+ state_approve_md = fields.Selection([
+ ('waiting', 'Waiting For Approve by MD'),
+ ('pending', 'Pending (perlu koordinasi dengan MD)'),
+ ('done', 'Approve by MD'),
+ ], string='Approval MD Gudang Selisih', tracking=True, copy=False, help="The current state of the MD Approval transfer barang from gudang selisih.")
+ show_state_approve_md = fields.Boolean(compute="_compute_show_state_approve_md")
+
+ def _compute_show_state_approve_md(self):
+ for record in self:
+ record.show_state_approve_md = record.location_id.id == 47 or record.location_id.complete_name == "Virtual Locations/Gudang Selisih"
@api.model
def _compute_dokumen_tanda_terima(self):
@@ -891,8 +901,36 @@ class StockPicking(models.Model):
qty_onhand = check_qty_per_inventory(self, line.product_id, line.location_id)
if line.qty_done > qty_onhand:
raise UserError('Quantity Done melebihi Quantity Onhand')
+ def button_state_approve_md(self):
+ group_id = self.env.ref('indoteknik_custom.group_role_merchandiser').id
+ users_in_group = self.env['res.users'].search([('groups_id', 'in', [group_id])])
+ active_model = self.env.context.get('active_model')
+ if self.env.user.id in users_in_group.mapped('id'):
+ self.state_approve_md = 'done'
+ else:
+ raise UserError('Hanya MD yang bisa Approve')
+
+ def button_state_pending_md(self):
+ group_id = self.env.ref('indoteknik_custom.group_role_merchandiser').id
+ users_in_group = self.env['res.users'].search([('groups_id', 'in', [group_id])])
+ active_model = self.env.context.get('active_model')
+ if self.env.user.id in users_in_group.mapped('id'):
+ self.state_approve_md = 'pending'
+ else:
+ raise UserError('Hanya MD yang bisa Approve')
def button_validate(self):
+ group_id = self.env.ref('indoteknik_custom.group_role_merchandiser').id
+ users_in_group = self.env['res.users'].search([('groups_id', 'in', [group_id])])
+ active_model = self.env.context.get('active_model')
+ if self.location_id.id == 47 and self.env.user.id not in users_in_group.mapped('id') and self.state_approve_md != 'done':
+ self.state_approve_md = 'waiting' if self.state_approve_md != 'pending' else 'pending'
+ self.env.cr.commit()
+ raise UserError("Transfer dari gudang selisih harus di approve MD, Hubungi MD agar bisa di Validate")
+ else:
+ if self.location_id.id == 47 and self.env.user.id in users_in_group.mapped('id'):
+ self.state_approve_md = 'done'
+
if not self.env.user.is_logistic_approver and self.env.context.get('active_model') == 'stock.picking':
if self.origin and 'Return of' in self.origin:
raise UserError("Button ini hanya untuk Logistik")
@@ -917,7 +955,7 @@ class StockPicking(models.Model):
if self.picking_type_id.id == 28 and not self.env.user.is_logistic_approver:
raise UserError("Harus di Approve oleh Logistik")
-
+
if self.location_dest_id.id == 47 and not self.env.user.is_purchasing_manager:
raise UserError("Transfer ke gudang selisih harus di approve Rafly Hanggara")
@@ -1018,9 +1056,12 @@ class StockPicking(models.Model):
return True
def action_cancel(self):
- if not self.env.user.is_logistic_approver and self.env.context.get('active_model') == 'stock.picking':
+ if not self.env.user.is_logistic_approver:
if self.origin and 'Return of' in self.origin:
raise UserError("Button ini hanya untuk Logistik")
+
+ if not self.env.user.has_group('indoteknik_custom.group_role_it') and not self.env.user.has_group('indoteknik_custom.group_role_logistic'):
+ raise UserError("Button ini hanya untuk Logistik")
res = super(StockPicking, self).action_cancel()
return res
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index 4d9d8cf7..4d0e51eb 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -167,3 +167,4 @@ access_barcoding_product_line,access.barcoding.product.line,model_barcoding_prod
access_account_payment_register,access.account.payment.register,model_account_payment_register,,1,1,1,1
access_stock_inventory,access.stock.inventory,model_stock_inventory,,1,1,1,1
access_cancel_reason_order,cancel.reason.order,model_cancel_reason_order,,1,1,1,0
+access_shipping_option,shipping.option,model_shipping_option,,1,1,1,1
diff --git a/indoteknik_custom/views/customer_commision.xml b/indoteknik_custom/views/customer_commision.xml
index 51172b1c..bb1628bc 100644
--- a/indoteknik_custom/views/customer_commision.xml
+++ b/indoteknik_custom/views/customer_commision.xml
@@ -17,6 +17,8 @@
decoration-danger="payment_status == 'pending'"
widget="badge"/>
<field name="brand_ids" widget="many2many_tags"/>
+ <field name="grouped_so_number" readonly="1"/>
+ <field name="grouped_invoice_number" readonly="1"/>
</tree>
</field>
</record>
@@ -62,6 +64,8 @@
<field name="description"/>
<field name="commision_percent"/>
<field name="commision_amt"/>
+ <field name="grouped_so_number" readonly="1"/>
+ <field name="grouped_invoice_number" readonly="1"/>
</group>
<group>
<div>
diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml
index ebee64b1..0d190f37 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -100,6 +100,7 @@
<field name="sales_tax_id" domain="[('type_tax_use','=','sale'), ('active', '=', True)]" required="1"/>
<field name="carrier_id" required="1"/>
<field name="delivery_service_type" readonly="1"/>
+ <field name="shipping_option_id"/>
</field>
<field name="medium_id" position="after">
<field name="date_doc_kirim" readonly="1"/>
diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml
index dadd5021..ce07888a 100644
--- a/indoteknik_custom/views/stock_picking.xml
+++ b/indoteknik_custom/views/stock_picking.xml
@@ -19,7 +19,8 @@
<field name="note" optional="hide"/>
<field name="date_reserved" optional="hide"/>
<field name="state_reserve" optional="hide"/>
- <field name="final_seq"/>
+ <field name="final_seq"/>
+<!-- <field name="state_approve_md" widget="badge" decoration-success="state_approve_md == 'done'" decoration-warning="state_approve_md == 'pending'" />-->
<!-- <field name="countdown_hours" optional="hide"/>
<field name="countdown_ready_to_ship" /> -->
</field>
@@ -70,6 +71,17 @@
type="object"
attrs="{'invisible': [('carrier_id', '!=', 9)]}"
/>
+<!-- <button name="button_state_approve_md"-->
+<!-- string="Approve MD Gudang Selisih"-->
+<!-- type="object"-->
+<!-- attrs="{'invisible': [('state_approve_md', 'not in', ['waiting', 'pending'])]}"-->
+<!-- />-->
+
+<!-- <button name="button_state_pending_md"-->
+<!-- string="Pending MD Gudang Selisih"-->
+<!-- type="object"-->
+<!-- attrs="{'invisible': [('state_approve_md', 'not in', ['waiting'])]}"-->
+<!-- />-->
</button>
<field name="backorder_id" position="after">
<field name="summary_qty_detail"/>
@@ -97,6 +109,8 @@
<field name="arrival_time"/>
</field>
<field name="origin" position="after">
+<!-- <field name="show_state_approve_md" invisible="1" optional="hide"/>-->
+<!-- <field name="state_approve_md" widget="badge" attrs="{'invisible': [('show_state_approve_md', '=', False)]}"/>-->
<field name="purchase_id"/>
<field name="sale_order"/>
<field name="invoice_status"/>