summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indoteknik_api/controllers/api_v1/sale_order.py7
-rw-r--r--indoteknik_api/controllers/api_v1/user.py8
-rw-r--r--indoteknik_api/controllers/api_v1/voucher.py22
-rwxr-xr-xindoteknik_custom/__manifest__.py1
-rwxr-xr-xindoteknik_custom/models/__init__.py1
-rw-r--r--indoteknik_custom/models/commision.py18
-rw-r--r--indoteknik_custom/models/coretax_fatur.py1
-rwxr-xr-xindoteknik_custom/models/purchase_order_line.py60
-rw-r--r--indoteknik_custom/models/purchase_order_sales_match.py12
-rw-r--r--indoteknik_custom/models/requisition.py42
-rwxr-xr-xindoteknik_custom/models/res_users.py4
-rwxr-xr-xindoteknik_custom/models/sale_order.py83
-rw-r--r--indoteknik_custom/models/stock_inventory.py59
-rw-r--r--indoteknik_custom/models/stock_picking.py4
-rw-r--r--indoteknik_custom/models/voucher.py6
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv2
-rw-r--r--indoteknik_custom/views/customer_commision.xml9
-rwxr-xr-xindoteknik_custom/views/purchase_order.xml6
-rw-r--r--indoteknik_custom/views/res_users.xml2
-rwxr-xr-xindoteknik_custom/views/sale_order.xml25
-rw-r--r--indoteknik_custom/views/stock_inventory.xml28
-rwxr-xr-xindoteknik_custom/views/voucher.xml1
22 files changed, 369 insertions, 32 deletions
diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py
index 4afeb21b..6815bf6c 100644
--- a/indoteknik_api/controllers/api_v1/sale_order.py
+++ b/indoteknik_api/controllers/api_v1/sale_order.py
@@ -395,7 +395,8 @@ class SaleOrder(controller.Controller):
# Fetch partner details
sales_partner = request.env['res.partner'].browse(params['value']['partner_id'])
-
+ partner_invoice = request.env['res.partner'].browse(params['value']['partner_invoice_id'])
+ main_partner = partner_invoice.get_main_parent()
parameters = {
'warehouse_id': 8,
'carrier_id': 1,
@@ -411,7 +412,7 @@ class SaleOrder(controller.Controller):
'partner_id': params['value']['partner_id'],
'partner_shipping_id': params['value']['partner_shipping_id'],
'real_shipping_id': params['value']['partner_shipping_id'],
- 'partner_invoice_id': params['value']['partner_invoice_id'],
+ 'partner_invoice_id': main_partner.id,
'real_invoice_id': params['value']['partner_invoice_id'],
'partner_purchase_order_name': params['value']['po_number'],
'partner_purchase_order_file': params['value']['po_file'],
@@ -428,7 +429,7 @@ class SaleOrder(controller.Controller):
'npwp': sales_partner.npwp or '0', # Get NPWP from partner
'sppkp': sales_partner.sppkp, # Get SPPKP from partner
'email': sales_partner.email, # Get Email from partner
- 'user_id': 3222 # User ID: Nadia Rauhadatul Firdaus
+ 'user_id': 11314 # User ID: Boy Revandi
}
sales_partner = request.env['res.partner'].browse(parameters['partner_id'])
diff --git a/indoteknik_api/controllers/api_v1/user.py b/indoteknik_api/controllers/api_v1/user.py
index 1d26d356..c0974367 100644
--- a/indoteknik_api/controllers/api_v1/user.py
+++ b/indoteknik_api/controllers/api_v1/user.py
@@ -98,7 +98,7 @@ class User(controller.Controller):
user.partner_id.npwp = '00.000.000.0-000.000'
user.partner_id.sppkp = '-'
user.partner_id.nama_wajib_pajak = user.name
- user.partner_id.user_id = 3222
+ user.partner_id.user_id = 11314
user.partner_id.property_account_receivable_id = 395
user.partner_id.property_account_payable_id = 438
data = {
@@ -208,7 +208,7 @@ class User(controller.Controller):
'email': email_partner,
'street': alamat_bisnis,
'company_type': 'company',
- 'user_id': 3222,
+ 'user_id': 11314,
'property_account_receivable_id': 395,
'property_account_payable_id': 438,
'active': False,
@@ -253,7 +253,7 @@ class User(controller.Controller):
user.partner_id.npwp = '00.000.000.0-000.000'
user.partner_id.sppkp = '-'
user.partner_id.nama_wajib_pajak = name
- user.partner_id.user_id = 3222
+ user.partner_id.user_id = 11314
user.partner_id.property_account_receivable_id= 395
user.partner_id.property_account_payable_id = 438
@@ -605,7 +605,7 @@ class User(controller.Controller):
'email': email_partner,
'street': alamat_bisnis,
'company_type': 'company',
- 'user_id': 3222,
+ 'user_id': 11314,
'property_account_receivable_id': 395,
'property_account_payable_id': 438,
'active': False,
diff --git a/indoteknik_api/controllers/api_v1/voucher.py b/indoteknik_api/controllers/api_v1/voucher.py
index 910488d1..9ffeeace 100644
--- a/indoteknik_api/controllers/api_v1/voucher.py
+++ b/indoteknik_api/controllers/api_v1/voucher.py
@@ -22,9 +22,14 @@ class Voucher(controller.Controller):
code = kw.get('code')
type = kw.get('type')
user_id = int(kw.get('user_id', 0))
+ partner_id = int(kw.get('partner_id', 0))
source = kw.get('source')
visibility = ['public']
+ user = request.env['res.users'].search([('id', '=', user_id)], limit=1)
+ if not user:
+ return self.response([])
+
domain = []
if code:
visibility.append('private')
@@ -37,14 +42,19 @@ class Voucher(controller.Controller):
type = type.split(',')
domain += [('apply_type', 'in', type)]
+ if partner_id:
+ partner = request.env['res.partner'].search([('id', '=', partner_id)], limit=1)
+ main_parent = partner.get_main_parent()
+ if main_parent and main_parent.company_type:
+ domain += [('account_type', 'in', ['all',main_parent.company_type])]
+ # domain += [('account_type', 'in', main_parent.company_type)]
+
+
domain += [('visibility', 'in', visibility)]
vouchers = request.env['voucher'].get_active_voucher(domain)
checkout = cart.get_user_checkout(user_id, source=source)
products = checkout['products']
- user = request.env['res.users'].search([('id', '=', user_id)], limit=1)
- if not user:
- return self.response([])
order_line = []
for product in products:
@@ -89,3 +99,9 @@ class Voucher(controller.Controller):
sorted_results = sorted(results, key=lambda x: x['can_apply'], reverse=True)
return self.response(sorted_results)
+
+ def get_user_by_email(self, email):
+ return request.env['res.users'].search([
+ ('login', '=', email),
+ ('active', 'in', [True, False])
+ ]) \ No newline at end of file
diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py
index 38c60f50..e031cdcb 100755
--- a/indoteknik_custom/__manifest__.py
+++ b/indoteknik_custom/__manifest__.py
@@ -163,6 +163,7 @@
'views/vendor_sla.xml',
'views/coretax_faktur.xml',
'views/public_holiday.xml',
+ 'views/stock_inventory.xml',
],
'demo': [],
'css': [],
diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py
index ed9d69be..12f2246a 100755
--- a/indoteknik_custom/models/__init__.py
+++ b/indoteknik_custom/models/__init__.py
@@ -145,3 +145,4 @@ from . import public_holiday
from . import ir_actions_report
from . import barcoding_product
from . import account_payment_register
+from . import stock_inventory
diff --git a/indoteknik_custom/models/commision.py b/indoteknik_custom/models/commision.py
index 48f1c7f6..6920154a 100644
--- a/indoteknik_custom/models/commision.py
+++ b/indoteknik_custom/models/commision.py
@@ -153,6 +153,10 @@ class CustomerCommision(models.Model):
bank_account = fields.Char(string='Account No', tracking=3)
note_transfer = fields.Char(string='Keterangan')
brand_ids = fields.Many2many('x_manufactures', string='Brands')
+ payment_status = fields.Selection([
+ ('pending', 'Pending'),
+ ('payment', 'Payment'),
+ ], string='Payment Status', copy=False, readonly=True, tracking=3, default='pending')
# add status for type of commision, fee, rebate / cashback
# include child or not?
@@ -228,6 +232,20 @@ class CustomerCommision(models.Model):
raise UserError('Harus di approved oleh yang bersangkutan')
return
+ def action_confirm_customer_payment(self):
+ if self.status != 'approved':
+ raise UserError('Commision harus di approve terlebih dahulu sebelum di konfirmasi pembayarannya')
+
+ if self.payment_status == 'payment':
+ raise UserError('Customer Commision sudah berstatus Payment')
+ group_id = self.env.ref('indoteknik_custom.group_role_fat').id
+ users_in_group = self.env['res.users'].search([('groups_id', 'in', [group_id])])
+ if self.env.user.id not in users_in_group.mapped('id'):
+ raise UserError('Hanya bisa dikonfirmasi oleh FAT')
+ else:
+ self.payment_status = 'payment'
+ return
+
def generate_customer_commision(self):
if self.commision_lines:
raise UserError('Line sudah ada, tidak bisa di generate ulang')
diff --git a/indoteknik_custom/models/coretax_fatur.py b/indoteknik_custom/models/coretax_fatur.py
index 706a4f44..b4bffbd2 100644
--- a/indoteknik_custom/models/coretax_fatur.py
+++ b/indoteknik_custom/models/coretax_fatur.py
@@ -59,6 +59,7 @@ class CoretaxFaktur(models.Model):
ET.SubElement(tax_invoice, 'TrxCode').text = '04'
ET.SubElement(tax_invoice, 'AddInfo')
ET.SubElement(tax_invoice, 'CustomDoc')
+ ET.SubElement(tax_invoice, 'CustomDocMonthYear')
ET.SubElement(tax_invoice, 'RefDesc').text = invoice.name
ET.SubElement(tax_invoice, 'FacilityStamp')
ET.SubElement(tax_invoice, 'SellerIDTKU').text = '0742260227086000000000'
diff --git a/indoteknik_custom/models/purchase_order_line.py b/indoteknik_custom/models/purchase_order_line.py
index 587a09a1..033469b8 100755
--- a/indoteknik_custom/models/purchase_order_line.py
+++ b/indoteknik_custom/models/purchase_order_line.py
@@ -321,32 +321,60 @@ class PurchaseOrderLine(models.Model):
def compute_item_margin(self):
sum_so_margin = sum_sales_price = sum_margin = 0
+
for line in self:
- if not line.product_id or line.product_id.type == 'service' or not self.order_id.sale_order_id:
+ product = line.product_id
+ order = line.order_id
+
+ # Skip jika tidak ada product_id, produk adalah service, atau tidak ada purchase order terkait
+ if not product or product.type == 'service' or not order:
line.so_item_margin = 0
line.so_item_percent_margin = 0
line.item_margin = 0
line.item_percent_margin = 0
continue
- sale_order_line = self.env['sale.order.line'].search(
- [('product_id', '=', line.product_id.id),
- ('order_id', '=', line.order_id.sale_order_id.id)], limit=1, order='price_reduce_taxexcl')
- line.so_item_margin = sale_order_line.item_margin
- line.so_item_percent_margin = sale_order_line.item_percent_margin
- sum_so_margin += sale_order_line.item_margin
- sales_price = sale_order_line.price_reduce_taxexcl * sale_order_line.product_uom_qty
- if sale_order_line.order_id.shipping_cost_covered == 'indoteknik':
- sales_price -= sale_order_line.delivery_amt_line
- if sale_order_line.order_id.fee_third_party > 0:
- sales_price -= sale_order_line.fee_third_party_line
- sum_sales_price += sales_price
+
+ # Cari semua sale.order.line terkait dengan purchase.order melalui tabel purchase.order.sales.match
+ sales_matches = self.env['purchase.order.sales.match'].search([
+ ('purchase_order_id', '=', order.id),
+ ('product_id', '=', product.id)
+ ])
+
+ total_sales_price = total_margin = total_qty_so = 0
+ for match in sales_matches:
+ sale_order_line = match.sale_line_id
+
+ # Hitung harga jual setelah mempertimbangkan biaya tambahan
+ sales_price = sale_order_line.price_reduce_taxexcl * match.qty_so
+ if sale_order_line.order_id.shipping_cost_covered == 'indoteknik':
+ sales_price -= sale_order_line.delivery_amt_line
+ if sale_order_line.order_id.fee_third_party > 0:
+ sales_price -= sale_order_line.fee_third_party_line
+
+ total_sales_price += sales_price
+ total_margin += sale_order_line.item_margin
+ total_qty_so += match.qty_so
+
+ # Set margin berdasarkan total dari semua sales order yang terkait
+ line.so_item_margin = total_margin
+ line.so_item_percent_margin = (total_margin / total_sales_price) * 100 if total_sales_price else 0
+
+ sum_so_margin += total_margin
+ sum_sales_price += total_sales_price
+
+ # Hitung harga pembelian dengan mempertimbangkan biaya pengiriman
purchase_price = line.price_subtotal
- if line.order_id.delivery_amount > 0:
+ if order.delivery_amount > 0:
purchase_price += line.delivery_amt_line
- real_item_margin = sales_price - purchase_price
- real_item_percent_margin = round((real_item_margin/sales_price), 2) * 100
+
+ # Hitung margin dan persentase margin
+ real_item_margin = total_sales_price - purchase_price
+ real_item_percent_margin = (real_item_margin / total_sales_price) * 100 if total_sales_price else 0
+
+ # Set nilai margin ke dalam line
line.item_margin = real_item_margin
line.item_percent_margin = real_item_percent_margin
+
sum_margin += real_item_margin
def compute_delivery_amt_line(self):
diff --git a/indoteknik_custom/models/purchase_order_sales_match.py b/indoteknik_custom/models/purchase_order_sales_match.py
index d1d929d3..ed013dd5 100644
--- a/indoteknik_custom/models/purchase_order_sales_match.py
+++ b/indoteknik_custom/models/purchase_order_sales_match.py
@@ -24,6 +24,18 @@ class PurchaseOrderSalesMatch(models.Model):
margin_item = fields.Float(string='Margin')
delivery_amt = fields.Float(string='Delivery Amount', compute='_compute_delivery_amt')
margin_deduct = fields.Float(string='After Deduct', compute='_compute_delivery_amt')
+ purchase_price_so = fields.Float(string='Purchase Price Sale Order', related='sale_line_id.purchase_price')
+ purchase_price_po = fields.Float('Purchase Price PO', compute='_compute_purchase_price_po')
+ purchase_line_id = fields.Many2one('purchase.order.line', string='Purchase Line', compute='_compute_purchase_line_id')
+
+ def _compute_purchase_line_id(self):
+ for line in self:
+ line.purchase_line_id = self.env['purchase.order.line'].search([('order_id', '=', line.purchase_order_id.id), ('product_id', '=', line.product_id.id)])
+
+ def _compute_purchase_price_po(self):
+ for line in self:
+ purchase_price = self.env['purchase.order.line'].search([('order_id', '=', line.purchase_order_id.id), ('product_id', '=', line.product_id.id)])
+ line.purchase_price_po = purchase_price.price_unit
def _compute_delivery_amt(self):
for line in self:
diff --git a/indoteknik_custom/models/requisition.py b/indoteknik_custom/models/requisition.py
index c972b485..1d350929 100644
--- a/indoteknik_custom/models/requisition.py
+++ b/indoteknik_custom/models/requisition.py
@@ -276,10 +276,11 @@ class RequisitionLine(models.Model):
_name = 'requisition.line'
_description = 'Requisition Line'
_order = 'requisition_id, id'
+ _inherit = ['mail.thread']
requisition_id = fields.Many2one('requisition', string='Ref', required=True, ondelete='cascade', index=True, copy=False)
brand_id = fields.Many2one('x_manufactures', string='Brand')
- product_id = fields.Many2one('product.product', string='Product')
+ product_id = fields.Many2one('product.product', string='Product', tracking=3,)
partner_id = fields.Many2one('res.partner', string='Vendor')
qty_purchase = fields.Float(string='Qty Purchase')
price_unit = fields.Float(string='Price')
@@ -331,6 +332,45 @@ class RequisitionLine(models.Model):
line.taxes_id = taxes
line.partner_id = purchase_pricelist.vendor_id.id
+ @api.model
+ def create(self, vals):
+ record = super(RequisitionLine, self).create(vals)
+ record._track_changes('Tambah')
+ return record
+
+ def write(self, vals):
+ for record in self:
+ old_values = {field: record[field] for field in vals if field in record}
+
+ result = super(RequisitionLine, self).write(vals)
+
+ for record in self:
+ record._track_changes('Updated', old_values)
+
+ return result
+
+ def unlink(self):
+ for record in self:
+ record._track_changes('Hapus')
+ return super(RequisitionLine, self).unlink()
+
+ def _track_changes(self, action, old_values=None):
+ message = f"Produk telah di-{action} : <br/>"
+ if action == 'Tambah':
+ # message += f"<br/> Product: {self.product_id.name}"
+ message += f"Product: {self.product_id.name} <br/> Vendor: {self.partner_id.name} <br/> Qty: {self.qty_purchase} <br/> Price: {self.price_unit} <br/> Tax: {self.tax_id.name} <br/> Subtotal: {self.subtotal} <br/> Brand: {self.brand_id.x_name}"
+ elif action == 'Hapus':
+ # message += f"<br/> Deleted Product: {self.product_id.name}"
+ message += f"<br/> Deleted Product: {self.product_id.name} <br/> Vendor: {self.partner_id.name} Qty: {self.qty_purchase} <br/> Price: {self.price_unit} <br/> Tax: {self.tax_id.name} <br/> Subtotal: {self.subtotal} <br/> Brand: {self.brand_id.x_name}"
+ else: # Updated
+ for field, old_value in old_values.items():
+ new_value = self[field]
+ if old_value != new_value:
+ field_label = self._fields[field].string # Ambil nama label field
+ message += f"{field_label}: {old_value} -> {new_value}<br/>"
+
+ if self.requisition_id:
+ self.requisition_id.message_post(body=message)
class RequisitionPurchaseMatch(models.Model):
_name = 'requisition.purchase.match'
diff --git a/indoteknik_custom/models/res_users.py b/indoteknik_custom/models/res_users.py
index 31b84ae3..b0864f2c 100755
--- a/indoteknik_custom/models/res_users.py
+++ b/indoteknik_custom/models/res_users.py
@@ -70,6 +70,10 @@ class ResUsers(models.Model):
vouchers = self.env['voucher'].get_active_voucher([('show_on_email', '=', 'user_activation')])
if not vouchers: return None
return ', '.join(x.code for x in vouchers)
+ if type == 'switch_account':
+ vouchers = self.env['voucher'].get_active_voucher([('excl_pricelist_ids', 'not in', [1]), ('apply_type', 'in', ['all', 'brand']), ('account_type', 'in', ['all', 'company']), ('visibility', 'in', ['public'])])
+ if not vouchers: return None
+ return ', '.join(x.code for x in vouchers)
return None
def check_access(self, model, mode):
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index 634ea918..93c2276a 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -7,6 +7,49 @@ from collections import defaultdict
_logger = logging.getLogger(__name__)
+class CancelReasonOrder(models.TransientModel):
+ _name = 'cancel.reason.order'
+ _description = 'Wizard for Cancel Reason order'
+
+ request_id = fields.Many2one('sale.order', string='Request')
+ reason_cancel = fields.Selection([
+ ('harga_terlalu_mahal', 'Harga barang terlalu mahal'),
+ ('harga_web_tidak_valid', 'Harga web tidak valid'),
+ ('stok_kosong', 'Stock kosong'),
+ ('tidak_mau_indent', 'Customer tidak mau indent'),
+ ('batal_rencana_pembelian', 'Customer membatalkan rencana pembelian'),
+ ('vendor_tidak_support_demo', 'Vendor tidak support demo/trial product'),
+ ('product_knowledge_kurang', 'Product knowledge kurang baik'),
+ ('barang_tidak_sesuai', 'Barang tidak sesuai/tepat'),
+ ('tidak_sepakat_pembayaran', 'Tidak menemukan kesepakatan untuk pembayaran'),
+ ('dokumen_tidak_support', 'Indoteknik tidak bisa support document yang dibutuhkan (Ex: TKDN, COO, SNI)'),
+ ('ganti_quotation', 'Ganti Quotation'),
+ ('testing_internal', 'Testing Internal'),
+ ], string='Reason for Cancel', required=True, copy=False, index=True, tracking=3)
+ attachment_bukti = fields.Many2many(
+ 'ir.attachment',
+ string="Attachment Bukti", readonly=False,
+ tracking=3, required=True
+ )
+ nomor_so_pengganti = fields.Char(string='Nomor SO Pengganti', copy=False, tracking=3)
+
+ def confirm_reject(self):
+ order = self.request_id
+ if order:
+ order.write({'reason_cancel': self.reason_cancel})
+ if not self.attachment_bukti:
+ raise UserError('Attachment bukti wajib disertakan')
+ order.write({'attachment_bukti': self.attachment_bukti})
+ order.message_post(body='Attachment Bukti Cancel',
+ attachment_ids=[self.attachment_bukti.id])
+ if self.reason_cancel == 'ganti_quotation':
+ if self.nomor_so_pengganti:
+ order.write({'nomor_so_pengganti': self.nomor_so_pengganti})
+ else:
+ raise UserError('Nomor SO pengganti wajib disertakan')
+ order.confirm_cancel_order()
+
+ return {'type': 'ir.actions.act_window_close'}
class SaleOrder(models.Model):
_inherit = "sale.order"
@@ -157,6 +200,26 @@ class SaleOrder(models.Model):
)
shipping_method_picking = fields.Char(string='Shipping Method Picking', compute='_compute_shipping_method_picking')
+ reason_cancel = fields.Selection([
+ ('harga_terlalu_mahal', 'Harga barang terlalu mahal'),
+ ('harga_web_tidak_valid', 'Harga web tidak valid'),
+ ('stok_kosong', 'Stock kosong'),
+ ('tidak_mau_indent', 'Customer tidak mau indent'),
+ ('batal_rencana_pembelian', 'Customer membatalkan rencana pembelian'),
+ ('vendor_tidak_support_demo', 'Vendor tidak support demo/trial product'),
+ ('product_knowledge_kurang', 'Product knowledge kurang baik'),
+ ('barang_tidak_sesuai', 'Barang tidak sesuai/tepat'),
+ ('tidak_sepakat_pembayaran', 'Tidak menemukan kesepakatan untuk pembayaran'),
+ ('dokumen_tidak_support', 'Indoteknik tidak bisa support document yang dibutuhkan (Ex: TKDN, COO, SNI)'),
+ ('ganti_quotation', 'Ganti Quotation'),
+ ('testing_internal', 'Testing Internal'),
+ ], string='Reason for Cancel', copy=False, index=True, tracking=3)
+ attachment_bukti = fields.Many2one(
+ 'ir.attachment',
+ string="Attachment Bukti Cancel", readonly=False,
+ )
+ nomor_so_pengganti = fields.Char(string='Nomor SO Pengganti', copy=False, tracking=3)
+
def _compute_shipping_method_picking(self):
for order in self:
if order.picking_ids:
@@ -1155,8 +1218,24 @@ class SaleOrder(models.Model):
self.due_id = False
if main_parent.use_so_approval:
self.send_notif_to_salesperson(cancel=True)
+ for order in self:
+ if order.amount_total > 30000000:
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': _('Cancel Reason'),
+ 'res_model': 'cancel.reason.order',
+ 'view_mode': 'form',
+ 'target': 'new',
+ 'context': {'default_request_id': self.id},
+ }
return super(SaleOrder, self).action_cancel()
-
+
+ def confirm_cancel_order(self):
+ """Fungsi ini akan dipanggil oleh wizard setelah alasan pembatalan dipilih"""
+ if self.state != 'cancel':
+ self.state = 'cancel'
+ return super(SaleOrder, self).action_cancel()
+
def validate_partner_invoice_due(self):
parent_id = self.partner_id.parent_id.id
parent_id = parent_id if parent_id else self.partner_id.id
@@ -1191,7 +1270,7 @@ class SaleOrder(models.Model):
return self.total_percent_margin < 15 and not self.env.user.is_leader
def _requires_approval_margin_manager(self):
- return self.total_percent_margin <= 20 and not self.env.user.is_leader and not self.env.user.is_sales_manager
+ return self.total_percent_margin >= 15 and not self.env.user.is_leader and not self.env.user.is_sales_manager
def _create_approval_notification(self, approval_role):
title = 'Warning'
diff --git a/indoteknik_custom/models/stock_inventory.py b/indoteknik_custom/models/stock_inventory.py
new file mode 100644
index 00000000..12a891de
--- /dev/null
+++ b/indoteknik_custom/models/stock_inventory.py
@@ -0,0 +1,59 @@
+from odoo import models, api, fields
+from odoo.exceptions import UserError
+from datetime import datetime
+import logging
+
+_logger = logging.getLogger(__name__)
+
+
+class StockInventory(models.Model):
+ _inherit = ['stock.inventory']
+ _order = 'id desc'
+ _rec_name = 'number'
+
+ number = fields.Char(string='Document No', index=True, copy=False, readonly=True)
+ adjusment_type = fields.Selection([
+ ('in', 'Adjusment In'),
+ ('out', 'Adjusment Out'),
+ ], string='Adjusments Type', required=True)
+
+ def _generate_number_stock_inventory(self):
+ """Men-generate nomor untuk semua stock inventory yang belum memiliki number."""
+ stock_records = self.env['stock.inventory'].search([('number', '=', False)], order='id asc')
+ for record in stock_records:
+ self._assign_number(record)
+
+ _logger.info('Generate Number Done')
+
+ def _assign_number(self, record):
+ """Menentukan nomor berdasarkan kategori Adjust-In atau Adjust-Out."""
+ name_upper = record.name.upper() if record.name else ""
+
+ if self.adjusment_type == 'out' or "ADJUST OUT" in name_upper or "ADJUST-OUT" in name_upper or "OUT" in name_upper:
+ last_number = self._get_last_sequence("ADJUST/OUT/")
+ record.number = f"ADJUST/OUT/{last_number}"
+ elif self.adjusment_type == 'in' or "ADJUST IN" in name_upper or "ADJUST-IN" in name_upper or "IN" in name_upper:
+ last_number = self._get_last_sequence("ADJUST/IN/")
+ record.number = f"ADJUST/IN/{last_number}"
+ else:
+ record.number = "UNKNOWN" # Jika tidak termasuk kategori
+
+ def _get_last_sequence(self, prefix):
+ """Mengambil nomor terakhir berdasarkan prefix (ADJUST/OUT/ atau ADJUST/IN/) dengan format 00001, 00002, dst."""
+ last_record = self.env['stock.inventory'].search(
+ [("number", "like", f"{prefix}%")], order="number desc", limit=1
+ )
+
+ if last_record and last_record.number:
+ try:
+ last_number = int(last_record.number.split("/")[-1]) # Ambil angka terakhir
+ return str(last_number + 1).zfill(5) # Format jadi 00001, 00002, dst.
+ except ValueError:
+ return "00001" # Jika format tidak valid, mulai dari 00001
+ return "00001" # Jika belum ada data, mulai dari 00001
+
+ @api.model
+ def create(self, vals):
+ order = super(StockInventory, self).create(vals)
+ self._assign_number(order)
+ return order
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index 696d25db..85cdc7eb 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -103,7 +103,7 @@ class StockPicking(models.Model):
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')
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')
+ date_reserved = fields.Datetime(string="Date Reserved", help='Tanggal ter-reserved semua barang nya', copy=False)
status_printed = fields.Selection([
('not_printed', 'Belum Print'),
('printed', 'Printed')
@@ -129,7 +129,7 @@ class StockPicking(models.Model):
('ready', 'Ready to Ship'),
('done', 'Done'),
('cancel', 'Cancelled'),
- ], string='Status Reserve', readonly=True, tracking=True, help="The current state of the stock picking.")
+ ], string='Status Reserve', tracking=True, copy=False, help="The current state of the stock picking.")
notee = fields.Text(string="Note")
@api.model
diff --git a/indoteknik_custom/models/voucher.py b/indoteknik_custom/models/voucher.py
index 37c97338..101d4bcf 100644
--- a/indoteknik_custom/models/voucher.py
+++ b/indoteknik_custom/models/voucher.py
@@ -59,7 +59,11 @@ class Voucher(models.Model):
show_on_email = fields.Selection([
('user_activation', 'User Activation')
], 'Show on Email')
-
+ account_type = fields.Selection(string='Account Type', default="all", selection=[
+ ('all', "All Account"),
+ ('person', "Account Individu"),
+ ('company', "Account Company"),
+ ])
@api.constrains('description')
def _check_description_length(self):
for record in self:
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index 37f5aeab..48c3dfb6 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -164,3 +164,5 @@ access_barcode_product,access.barcode.product,model_barcode_product,,1,1,1,1
access_barcoding_product,access.barcoding.product,model_barcoding_product,,1,1,1,1
access_barcoding_product_line,access.barcoding.product.line,model_barcoding_product_line,,1,1,1,1
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
diff --git a/indoteknik_custom/views/customer_commision.xml b/indoteknik_custom/views/customer_commision.xml
index 0b72587e..51172b1c 100644
--- a/indoteknik_custom/views/customer_commision.xml
+++ b/indoteknik_custom/views/customer_commision.xml
@@ -12,6 +12,10 @@
<field name="commision_percent"/>
<field name="commision_amt" readonly="1"/>
<field name="status" readonly="1"/>
+ <field name="payment_status" readonly="1"
+ decoration-success="payment_status == 'payment'"
+ decoration-danger="payment_status == 'pending'"
+ widget="badge"/>
<field name="brand_ids" widget="many2many_tags"/>
</tree>
</field>
@@ -43,6 +47,10 @@
<button name="action_confirm_customer_commision"
string="Confirm" type="object"
options="{}"/>
+ <button name="action_confirm_customer_payment"
+ string="Konfirmasi Pembayaran" type="object"
+ options="{}"
+ attrs="{'invisible': [('payment_status', '==', 'payment')], 'readonly': [('payment_status', '=', 'payment')]}"/>
</header>
<sheet string="Customer Commision">
<div class="oe_button_box" name="button_box"/>
@@ -68,6 +76,7 @@
<field name="brand_ids" widget="many2many_tags"/>
<field name="notification" readonly="1"/>
<field name="status" readonly="1"/>
+ <field name="payment_status" readonly="1" />
<field name="total_dpp"/>
</group>
</group>
diff --git a/indoteknik_custom/views/purchase_order.xml b/indoteknik_custom/views/purchase_order.xml
index 3e4dd89c..a57bd467 100755
--- a/indoteknik_custom/views/purchase_order.xml
+++ b/indoteknik_custom/views/purchase_order.xml
@@ -109,6 +109,10 @@
<field name="price_vendor" attrs="{'readonly': 1}" optional="hide"/>
</field>
<field name="price_subtotal" position="after">
+ <field name="so_item_margin" attrs="{'readonly': 1}" optional="hide"/>
+ <field name="so_item_percent_margin" attrs="{'readonly': 1}" optional="hide"/>
+ <field name="item_margin" attrs="{'readonly': 1}" optional="hide"/>
+ <field name="item_percent_margin" attrs="{'readonly': 1}" optional="hide"/>
<field name="so_line_id" attrs="{'readonly': 1}" optional="hide"/>
<field name="so_id" attrs="{'readonly': 1}" optional="hide"/>
<field name="indent" optional="hide"/>
@@ -296,6 +300,8 @@
<field name="partner_invoice_id"/>
<field name="salesperson_id"/>
<field name="product_id"/>
+ <field name="purchase_price_so"/>
+ <field name="purchase_price_po"/>
<field name="qty_so"/>
<field name="qty_po"/>
<field name="margin_item" optional="hide"/>
diff --git a/indoteknik_custom/views/res_users.xml b/indoteknik_custom/views/res_users.xml
index 9553bb91..5b35f9c4 100644
--- a/indoteknik_custom/views/res_users.xml
+++ b/indoteknik_custom/views/res_users.xml
@@ -236,6 +236,7 @@
<tr><td style="padding-bottom: 16px;"><b>Pembayaran Lengkap:</b> Pilih metode pembayaran yang sesuai dengan kebutuhan Anda, baik transfer bank, VA, kartu kredit, atau pembayaran tempo.</td></tr>
<tr><td style="padding-bottom: 16px;"><b>Pelacakan Pengiriman:</b> Lacak status pengiriman pesanan Anda secara real-time.</td></tr>
<tr><td style="padding-bottom: 16px;">Untuk memulai transaksi, silakan login Kembali menggunakan akun Anda di <a href="https://indoteknik.com/login">Indoteknik.com</a></td></tr>
+ <tr><td style="padding-bottom: 16px;">Gunakan kode voucher berikut untuk mendapatkan diskon belanja hingga 10 juta: <strong>${object.get_voucher_code('switch_account')}</strong></td></tr>
<tr><td style="padding-bottom: 16px;">Kami sangat senang dapat melayani Anda. Jika ada pertanyaan atau membutuhkan bantuan, jangan ragu untuk menghubungi tim layanan Customer kami di Whatsapp <a href="https://wa.me/6281717181922">0817-1718-1922</a> atau <a href="mailto:sales@indoteknik.com">sales@indoteknik.com</a></td></tr>
<tr><td style="padding-bottom: 2px;"><b>Hormat kami,</b></td></tr>
@@ -299,6 +300,7 @@
<tr><td style="padding-bottom: 16px;">Selamat! Akun bisnis Anda di indoteknik.com sekarang sudah resmi menjadi PKP dari yang sebelumnya Non-PKP.</td></tr>
<tr><td style="padding-bottom: 16px;">Jangan lupa untuk mengecek kembali semua data perusahaan kamu, ya. Pastikan NPWP dan informasi Perusahaan lainnya sudah kamu isi dengan benar.</td></tr>
+ <tr><td style="padding-bottom: 16px;">Gunakan kode voucher berikut untuk mendapatkan diskon belanja hingga 10 juta: <strong>${object.get_voucher_code('switch_account')}</strong></td></tr>
<tr><td style="padding-bottom: 16px;">Kamu juga dapat mengubah informasi perusahaan dengan mengunjungi profil atau <a href="https://indoteknik.com/my/profile">klik disini</a></td></tr>
<tr><td style="padding-bottom: 2px;">Industrial Supply &amp; Solutions</td></tr>
diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml
index 4cc96cd2..ebee64b1 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -286,6 +286,31 @@
</page>
</field>
</record>
+ <!-- Wizard for Reject Reason -->
+ <record id="view_cancel_reason_order_form" model="ir.ui.view">
+ <field name="name">cancel.reason.order.form</field>
+ <field name="model">cancel.reason.order</field>
+ <field name="arch" type="xml">
+ <form string="Cancel Reason">
+ <group>
+ <field name="reason_cancel" widget="selection"/>
+ <field name="attachment_bukti" widget="many2many_binary" required="1"/>
+ <field name="nomor_so_pengganti" attrs="{'invisible': [('reason_cancel', '!=', 'ganti_quotation')]}"/>
+ </group>
+ <footer>
+ <button string="Confirm" type="object" name="confirm_reject" class="btn-primary"/>
+ <button string="Cancel" class="btn-secondary" special="cancel"/>
+ </footer>
+ </form>
+ </field>
+ </record>
+
+ <record id="action_cancel_reason_order" model="ir.actions.act_window">
+ <field name="name">Cancel Reason</field>
+ <field name="res_model">cancel.reason.order</field>
+ <field name="view_mode">form</field>
+ <field name="target">new</field>
+ </record>
</data>
<data>
<record id="sale_order_tree_view_inherit" model="ir.ui.view">
diff --git a/indoteknik_custom/views/stock_inventory.xml b/indoteknik_custom/views/stock_inventory.xml
new file mode 100644
index 00000000..db85f05c
--- /dev/null
+++ b/indoteknik_custom/views/stock_inventory.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<odoo>
+ <!-- Form View: Tambahkan field 'number' setelah lokasi -->
+ <record id="view_stock_inventory_form_inherit" model="ir.ui.view">
+ <field name="name">stock.inventory.form.inherit</field>
+ <field name="model">stock.inventory</field>
+ <field name="inherit_id" ref="stock.view_inventory_form"/>
+ <field name="arch" type="xml">
+ <xpath expr="//field[@name='location_ids']" position="after">
+ <field name="number" readonly="1"/>
+ <field name="adjusment_type" />
+ </xpath>
+ </field>
+ </record>
+
+ <!-- Tree View: Tambahkan field 'number' setelah tanggal -->
+ <record id="view_stock_inventory_tree_inherit" model="ir.ui.view">
+ <field name="name">stock.inventory.tree.inherit</field>
+ <field name="model">stock.inventory</field>
+ <field name="inherit_id" ref="stock.view_inventory_tree"/>
+ <field name="arch" type="xml">
+ <xpath expr="//field[@name='date']" position="after">
+ <field name="number"/>
+ </xpath>
+ </field>
+ </record>
+
+</odoo>
diff --git a/indoteknik_custom/views/voucher.xml b/indoteknik_custom/views/voucher.xml
index 29d0ad4b..ae958f05 100755
--- a/indoteknik_custom/views/voucher.xml
+++ b/indoteknik_custom/views/voucher.xml
@@ -35,6 +35,7 @@
<field name="limit" required="1"/>
<field name="limit_user" required="1"/>
<field name="apply_type" required="1" />
+ <field name="account_type" required="1" />
<field name="show_on_email" />
<field name="excl_pricelist_ids" widget="many2many_tags" domain="[('id', 'in', [4, 15037, 15038, 15039, 17023, 17024, 17025, 17026,17027])]"/>
</group>