summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafi Zadanly <zadanlyr@gmail.com>2023-07-13 09:50:57 +0700
committerRafi Zadanly <zadanlyr@gmail.com>2023-07-13 09:50:57 +0700
commit32bf7b115ec71e72d9cde58bfa3c0304c4b1ffcb (patch)
tree19257db60cdd44a5527825825ab0032a2693f74d
parent3085bfa4333cbc99ed4a0e432c8313cf7009cd2a (diff)
parent604ef36b09c2eb2cf89f5b592ab775ba87e0ce88 (diff)
Merge remote-tracking branch 'origin/staging' into real-stock
-rw-r--r--indoteknik_api/controllers/api_v1/__init__.py1
-rw-r--r--indoteknik_api/controllers/api_v1/activity.py18
-rw-r--r--indoteknik_api/controllers/api_v1/sale_order.py3
-rw-r--r--indoteknik_api/controllers/controller.py7
-rw-r--r--indoteknik_api/models/product_product.py8
-rwxr-xr-xindoteknik_custom/__manifest__.py1
-rwxr-xr-xindoteknik_custom/models/__init__.py1
-rw-r--r--indoteknik_custom/models/account_move_due_extension.py161
-rw-r--r--indoteknik_custom/models/automatic_purchase.py7
-rw-r--r--indoteknik_custom/models/delivery_order.py3
-rwxr-xr-xindoteknik_custom/models/purchase_order.py13
-rw-r--r--indoteknik_custom/models/res_partner.py6
-rwxr-xr-xindoteknik_custom/models/sale_order.py160
-rw-r--r--indoteknik_custom/models/stock_picking.py16
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv2
-rw-r--r--indoteknik_custom/views/account_move_views.xml104
-rw-r--r--indoteknik_custom/views/delivery_order.xml1
-rw-r--r--indoteknik_custom/views/ir_sequence.xml10
-rwxr-xr-xindoteknik_custom/views/purchase_order.xml7
-rw-r--r--indoteknik_custom/views/res_partner.xml7
-rwxr-xr-xindoteknik_custom/views/sale_order.xml7
21 files changed, 517 insertions, 26 deletions
diff --git a/indoteknik_api/controllers/api_v1/__init__.py b/indoteknik_api/controllers/api_v1/__init__.py
index d05cdf3a..2afefb34 100644
--- a/indoteknik_api/controllers/api_v1/__init__.py
+++ b/indoteknik_api/controllers/api_v1/__init__.py
@@ -1,3 +1,4 @@
+from . import activity
from . import banner
from . import blog
from . import cart
diff --git a/indoteknik_api/controllers/api_v1/activity.py b/indoteknik_api/controllers/api_v1/activity.py
new file mode 100644
index 00000000..142db845
--- /dev/null
+++ b/indoteknik_api/controllers/api_v1/activity.py
@@ -0,0 +1,18 @@
+from .. import controller
+from odoo import http
+from odoo.http import request
+
+
+class Activity(controller.Controller):
+ @http.route('/api/v1/activity', auth='public', csrf=False, methods=['POST', 'OPTIONS'])
+ @controller.Controller.must_authorized()
+ def create_user_activity(self, **kw):
+ user_data = self.verify_user_token()
+ user_id = user_data['user_id'] if user_data else False
+ request.env['user.activity.log'].create({
+ 'page_title': kw.get('page_title', ''),
+ 'url': kw.get('url', ''),
+ 'res_user_id': user_id,
+ 'ip_address': kw.get('ip_address', '')
+ })
+ return self.response(True) \ No newline at end of file
diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py
index 671ff5a8..aa211b75 100644
--- a/indoteknik_api/controllers/api_v1/sale_order.py
+++ b/indoteknik_api/controllers/api_v1/sale_order.py
@@ -153,6 +153,7 @@ class SaleOrder(controller.Controller):
sale_order = request.env['sale.order'].search(domain)
if sale_order:
sale_order.partner_purchase_order_name = params['value']['name']
+ sale_order.client_order_ref = params['value']['name']
sale_order.partner_purchase_order_file = params['value']['file']
data = sale_order.id
return self.response(data)
@@ -265,6 +266,8 @@ class SaleOrder(controller.Controller):
'shipping_paid_by': 'customer',
'carrier_id': params['value']['carrier_id'],
'delivery_service_type': params['value']['delivery_service_type'],
+ 'customer_type': 'nonpkp',
+ 'npwp': '0'
}
if params['value']['type'] == 'sale_order':
parameters['approval_status'] = 'pengajuan1'
diff --git a/indoteknik_api/controllers/controller.py b/indoteknik_api/controllers/controller.py
index 90bc50ed..0fcf4814 100644
--- a/indoteknik_api/controllers/controller.py
+++ b/indoteknik_api/controllers/controller.py
@@ -108,7 +108,6 @@ class Controller(http.Controller):
return time
def response(self, data=[], code=200, description='OK', headers=[]):
- request.env['user.activity.log'].record_activity()
response = {
'status': {
'code': code,
@@ -169,6 +168,12 @@ class Controller(http.Controller):
def get_api_token(self, **kw):
return self.response(request.env['ir.config_parameter'].sudo().get_param('rest_api_token') or '')
+ @http.route('/api/ip-address', auth='public', methods=['GET', 'OPTIONS'])
+ def get_ip_address(self):
+ address = request.httprequest.remote_addr
+ address = address if address != '127.0.0.1' else False
+ return self.response(address)
+
@http.route('/api/image/<model>/<field>/<id>', auth='public', methods=['GET'])
def get_image(self, model, field, id):
model = request.env[model].sudo().search([('id', '=', id)], limit=1)
diff --git a/indoteknik_api/models/product_product.py b/indoteknik_api/models/product_product.py
index 14fe68cb..edf95a58 100644
--- a/indoteknik_api/models/product_product.py
+++ b/indoteknik_api/models/product_product.py
@@ -10,6 +10,8 @@ class ProductProduct(models.Model):
product_pricelist_default_discount_id = self.env['ir.config_parameter'].get_param('product.pricelist.default_discount_id')
product_pricelist_default_discount_id = int(product_pricelist_default_discount_id)
product_template = product_product.product_tmpl_id
+ stock = product_product.qty_stock_vendor
+ stock = stock if stock > 0 else 1
data = {
'id': product_product.id,
'parent': {
@@ -20,7 +22,7 @@ class ProductProduct(models.Model):
'code': product_product.default_code or '',
'name': product_product.display_name,
'price': self.env['product.pricelist'].compute_price(product_pricelist_default_discount_id, product_product.id),
- 'stock': product_product.qty_stock_vendor,
+ 'stock': stock,
'weight': product_product.weight,
'attributes': [x.name for x in product_product.product_template_attribute_value_ids],
'manufacture' : self.api_manufacture(product_product)
@@ -61,6 +63,8 @@ class ProductProduct(models.Model):
price_discount = flashsale_price
discount_percentage = flashsale_discount
+ stock = product_product.qty_stock_vendor
+ stock = stock if stock > 0 else 1
product_template = product_product.product_tmpl_id
data = {
'id': product_product.id,
@@ -76,7 +80,7 @@ class ProductProduct(models.Model):
'discount_percentage': discount_percentage,
'price_discount': price_discount
},
- 'stock': product_product.qty_stock_vendor,
+ 'stock': stock,
'weight': product_product.weight,
'attributes': [x.name for x in product_product.product_template_attribute_value_ids],
'manufacture' : self.api_manufacture(product_product)
diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py
index bba38a53..11921285 100755
--- a/indoteknik_custom/__manifest__.py
+++ b/indoteknik_custom/__manifest__.py
@@ -45,6 +45,7 @@
'views/uangmuka_penjualan.xml',
'views/sale_order.xml',
'views/account_asset_views.xml',
+ 'views/account_move_views.xml',
'views/ir_sequence.xml',
'views/stock_location.xml',
'views/stock_picking.xml',
diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py
index 8fd33b4a..4af46dae 100755
--- a/indoteknik_custom/models/__init__.py
+++ b/indoteknik_custom/models/__init__.py
@@ -65,3 +65,4 @@ from . import manufacturing
from . import requisition
from . import token_storage
from . import product_sla
+from . import account_move_due_extension
diff --git a/indoteknik_custom/models/account_move_due_extension.py b/indoteknik_custom/models/account_move_due_extension.py
new file mode 100644
index 00000000..1e3bdad1
--- /dev/null
+++ b/indoteknik_custom/models/account_move_due_extension.py
@@ -0,0 +1,161 @@
+from odoo import models, api, fields
+from odoo.exceptions import AccessError, UserError, ValidationError
+from datetime import timedelta, date
+import logging
+
+_logger = logging.getLogger(__name__)
+
+class DueExtension(models.Model):
+ _name = "due.extension"
+ _description = "Due Extension"
+ _inherit = ['mail.thread']
+ _rec_name = 'number'
+
+ number = fields.Char(string='Document No', index=True, copy=False, readonly=True, tracking=True)
+ partner_id = fields.Many2one('res.partner', string="Customer", readonly=True)
+ order_id = fields.Many2one('sale.order', string="SO", readonly=True)
+ due_line = fields.One2many('due.extension.line', 'due_id', string='Due Extension Lines', auto_join=True)
+ old_due = fields.Date(string="Old Due")
+ description = fields.Text(string="Description")
+ is_approve = fields.Boolean(string="Is Approve", readonly=True, tracking=True)
+ approval_status = fields.Selection([
+ ('pengajuan', 'Pengajuan'),
+ ('approved', 'Approved'),
+ ], string='Approval Status', readonly=True, copy=False, index=True, tracking=3)
+ day_extension = fields.Selection([
+ ('3', '3 Hari'),
+ ('7', '7 Hari'),
+ ('14', '14 Hari'),
+ ], string='Day Extension', help='Menambah Due Date yang sudah limit dari hari ini', tracking=True)
+ counter = fields.Integer(string="Counter", compute='_compute_counter')
+
+ def _compute_counter(self):
+ for due in self:
+ due.counter = due.partner_id.counter
+
+ @api.model
+ def create(self, vals):
+ vals['number'] = self.env['ir.sequence'].next_by_code('due.extension') or '0'
+ result = super(DueExtension, self).create(vals)
+ return result
+
+ def due_extension_approval(self):
+ if not self.approval_status:
+ self.approval_status = 'pengajuan'
+ elif self.approval_status == 'pengajuan':
+ raise UserError('Anda sudah mengajukan ask approval')
+ elif self.approval_status == 'approved':
+ raise UserError('Document sudah di approve')
+
+ def due_extension_cancel(self):
+ if self.env.user.is_accounting:
+ if not self.approval_status or self.approval_status == 'pengajuan':
+ self.approval_status = False
+ sales = self.env['sale.order'].search([
+ ('id', '=', self.order_id.id)
+ ])
+
+ sales.action_cancel()
+ elif self.approval_status == 'approved':
+ raise UserError('Document sudah di approve, Tidak bisa di cancel')
+ else:
+ raise UserError('Hanya Finance yang bisa cancel')
+
+ def approve_new_due(self):
+ if self.env.user.is_accounting:
+ if not self.approval_status == 'approved':
+ self.is_approve = True
+ self.approval_status = 'approved'
+
+ self.partner_id.counter+=1
+
+ if self.partner_id:
+ if self.day_extension:
+ day_extension = int(self.day_extension)
+ new_due = date.today() + timedelta(days=day_extension)
+
+ for line in self.due_line:
+ line.invoice_id.invoice_date_due = new_due
+
+ if self.order_id._notification_margin_leader():
+ self.order_id.approval_status = 'pengajuan2'
+ return self.order_id._notification_has_margin_leader()
+
+ if self.order_id._notification_margin_manager():
+ self.order_id.approval_status = 'pengajuan1'
+ return self.order_id._notification_has_margin_manager()
+
+ sales = self.env['sale.order'].search([
+ ('id', '=', self.order_id.id)
+ ])
+
+ # sales.state = 'sale'
+ sales.action_confirm()
+ self.order_id.due_id = self.id
+ else:
+ raise UserError('Document ini sudah di approve')
+ else:
+ raise UserError('Hanya Finance Yang Bisa Approve')
+
+ def generate_due_line(self):
+ partners = []
+ partners += self.partner_id.child_ids
+ partners.append(self.partner_id)
+
+
+ for partner in partners:
+ query = [
+ ('partner_id', '=', partner.id),
+ ('state', '=', 'posted'),
+ ('move_type', '=', 'out_invoice'),
+ ('amount_residual_signed', '>', 0)
+ ]
+ invoices = self.env['account.move'].search(query, order='invoice_date')
+ count = 0
+
+ for invoice in invoices:
+ if invoice.invoice_day_to_due < 0:
+ self.env['due.extension.line'].create([{
+ 'due_id': self.id,
+ 'partner_id': invoice.partner_id.id,
+ 'invoice_id': invoice.id,
+ 'date_invoice': invoice.invoice_date,
+ 'efaktur_id': invoice.efaktur_id.id,
+ 'reference': invoice.ref,
+ 'total_amt': invoice.amount_total,
+ 'open_amt': invoice.amount_residual_signed,
+ 'due_date': invoice.invoice_date_due
+ }])
+ count += 1
+ _logger.info("Due Extension Line generated %s" % count)
+ def unlink(self):
+ res = super(DueExtension, self).unlink()
+ if not self._name == 'due.extension':
+ raise UserError('Due Extension tidak bisa didelete')
+ return res
+
+
+class DueExtensionLine(models.Model):
+ _name = 'due.extension.line'
+ _description = 'Due Extension Line'
+ _order = 'due_id, id'
+
+ due_id = fields.Many2one('due.extension', string='Due Ref', required=True, ondelete='cascade', index=True, copy=False)
+ partner_id = fields.Many2one('res.partner', string='Customer')
+ invoice_id = fields.Many2one('account.move', string='Invoice')
+ date_invoice = fields.Date(string='Invoice Date')
+ efaktur_id = fields.Many2one('vit.efaktur', string='Faktur Pajak')
+ reference = fields.Char(string='Reference')
+ total_amt = fields.Float(string='Total Amount')
+ open_amt = fields.Float(string='Open Amount')
+ due_date = fields.Date(string='Due Date', compute="_compute_due_date")
+ day_to_due = fields.Integer(string='Day To Due', compute="_compute_day_to_due")
+
+ def _compute_day_to_due(self):
+ for line in self:
+ line.day_to_due = line.invoice_id.invoice_day_to_due
+
+ def _compute_due_date(self):
+ for line in self:
+ line.due_date = line.invoice_id.invoice_date_due
+
diff --git a/indoteknik_custom/models/automatic_purchase.py b/indoteknik_custom/models/automatic_purchase.py
index 87319bf6..e21b411d 100644
--- a/indoteknik_custom/models/automatic_purchase.py
+++ b/indoteknik_custom/models/automatic_purchase.py
@@ -59,11 +59,18 @@ class AutomaticPurchase(models.Model):
# new_po = self.env['purchase.order'].create([param_header])
brand_id = product.brand_id.id
count += 10
+
+ qty_available = product.product_id.qty_onhand_bandengan + product.product_id.qty_incoming_bandengan - product.product_id.outgoing_qty
+ suggest = 'harus beli'
+ if qty_available > product.qty_purchase:
+ suggest = 'masih cukup'
param_line = {
'order_id': new_po.id,
'sequence': count,
'product_id': product.product_id.id,
'product_qty': product.qty_purchase,
+ 'qty_available_store': qty_available,
+ 'suggest': suggest,
'product_uom_qty': product.qty_purchase,
'price_unit': product.last_price,
}
diff --git a/indoteknik_custom/models/delivery_order.py b/indoteknik_custom/models/delivery_order.py
index 3f8da384..be5fd2e0 100644
--- a/indoteknik_custom/models/delivery_order.py
+++ b/indoteknik_custom/models/delivery_order.py
@@ -74,6 +74,7 @@ class DeliveryOrderLine(models.TransientModel):
carrier_id = fields.Many2one('delivery.carrier', string='Shipping Method')
tracking_no = fields.Char(string='Tracking No')
delivery_order_id = fields.Many2one('delivery.order', string='Delivery Order')
+ partner_id = fields.Many2one('res.partner', string='Customer')
@api.onchange('name')
def onchange_name(self):
@@ -98,6 +99,8 @@ class DeliveryOrderLine(models.TransientModel):
self.tracking_no = picking.delivery_tracking_no
+ self.partner_id = picking.partner_id
+
delivery_type = self.get_delivery_type(picking.driver_departure_date, picking.driver_arrival_date)
if delivery_type != 'departure':
self.departure_date = picking.driver_departure_date.astimezone(timezone('Asia/Jakarta')).strftime('%Y-%m-%d %H:%M:%S')
diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py
index 13ff2931..7091bb72 100755
--- a/indoteknik_custom/models/purchase_order.py
+++ b/indoteknik_custom/models/purchase_order.py
@@ -191,6 +191,9 @@ class PurchaseOrder(models.Model):
raise UserError("Beda Margin dengan Sales, harus approval Manager")
if not self.sale_order_id and not self.env.user.is_purchasing_manager and not self.env.user.is_leader:
raise UserError("Tidak ada link dengan SO, harus approval Manager")
+ for line in self.order_line:
+ if not line.product_id.purchase_ok:
+ raise UserError("Terdapat barang yang tidak bisa di proses")
self.approval_status = 'approved'
self.po_status = 'menunggu'
@@ -212,6 +215,16 @@ class PurchaseOrder(models.Model):
else:
self.approval_status = 'pengajuan1'
+ def re_calculate(self):
+ for line in self.order_line:
+ 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')
+ for so_line in sale_order_line:
+ unit_price = line.price_unit
+ so_line.purchase_price = unit_price
+
def button_cancel(self):
res = super(PurchaseOrder, self).button_cancel()
self.approval_status = False
diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py
index 77abaaf9..5dec8da8 100644
--- a/indoteknik_custom/models/res_partner.py
+++ b/indoteknik_custom/models/res_partner.py
@@ -13,6 +13,12 @@ class ResPartner(models.Model):
company_type_id = fields.Many2one('res.partner.company_type', string='Company Type')
custom_pricelist_id = fields.Many2one('product.pricelist', string='Price Matrix')
group_partner_id = fields.Many2one('group.partner', string='Group Partner')
+ customer_type = fields.Selection([
+ ('pkp', 'PKP'),
+ ('nonpkp', 'Non PKP')
+ ])
+ sppkp = fields.Char(string="SPPKP")
+ counter = fields.Integer(string="Counter", default=0)
def unlink(self):
if self._name == 'res.partner':
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index 0a794f6d..5a3cada9 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -78,6 +78,21 @@ class SaleOrder(models.Model):
delivery_service_type = fields.Char(string='Delivery Service Type', help='data dari rajaongkir')
grand_total = fields.Monetary(string='Grand Total', help='Amount total + amount delivery', compute='_compute_grand_total')
payment_link_midtrans = fields.Char(string='Payment Link', help='Url payment yg digenerate oleh midtrans, harap diserahkan ke customer agar dapat dilakukan pembayaran secara mandiri')
+ due_id = fields.Many2one('due.extension', string="Due Extension", readonly=True, tracking=True)
+ customer_type = fields.Selection([
+ ('pkp', 'PKP'),
+ ('nonpkp', 'Non PKP')
+ ])
+ sppkp = fields.Char(string="SPPKP")
+ npwp = fields.Char(string="NPWP")
+ purchase_total = fields.Monetary(string='Purchase Total', compute='_compute_purchase_total')
+
+ def _compute_purchase_total(self):
+ for order in self:
+ total = 0
+ for line in order.order_line:
+ total += line.vendor_subtotal
+ order.purchase_total = total
def generate_payment_link_midtrans_sales_order(self):
# midtrans_url = 'https://app.sandbox.midtrans.com/snap/v1/transactions' # dev - sandbox
@@ -217,6 +232,15 @@ class SaleOrder(models.Model):
def onchange_partner_shipping(self):
self.real_shipping_id = self.partner_shipping_id
+ @api.onchange('partner_id')
+ def onchange_partner_contact(self):
+ parent_id = self.partner_id.parent_id
+ parent_id = parent_id if parent_id else self.partner_id
+
+ self.npwp = parent_id.npwp
+ self.sppkp = parent_id.sppkp
+ self.customer_type = parent_id.customer_type
+
def _get_purchases(self):
po_state = ['done', 'draft', 'purchase']
for order in self:
@@ -292,6 +316,7 @@ class SaleOrder(models.Model):
def sale_order_approve(self):
# raise UserError("Bisa langsung Confirm")
self.check_due()
+
for order in self:
if order.warehouse_id.id != 8: #GD Bandengan
raise UserError('Gudang harus Bandengan')
@@ -324,16 +349,20 @@ class SaleOrder(models.Model):
# must add product can sell validation
if not line.product_id.product_tmpl_id.sale_ok:
raise UserError('Product %s belum bisa dijual, harap hubungi finance' % line.product_id.display_name)
- if line.product_id.id == 232383:
+ if line.product_id.id == 224484:
raise UserError(_('Tidak bisa Confirm menggunakan Produk Sementara'))
if not line.vendor_id or not line.purchase_price:
raise UserError(_('Isi Vendor dan Harga Beli sebelum Request Approval'))
- if order.total_percent_margin <= 15 and not self.env.user.is_leader:
+
+ if order.validate_partner_invoice_due():
+ return self._notification_has_unapprove_due()
+
+ if order._notification_margin_leader():
order.approval_status = 'pengajuan2'
- elif order.total_percent_margin <= 22 and not self.env.user.is_leader and not self.env.user.is_sales_manager:
- order.approval_status = 'pengajuan1'
- elif order._have_outstanding_invoices() and not self.env.user.is_leader and not self.env.user.is_sales_manager:
+ return self._notification_has_margin_leader()
+ elif order._notification_margin_manager():
order.approval_status = 'pengajuan1'
+ return self._notification_has_margin_manager()
else:
raise UserError("Bisa langsung Confirm")
@@ -350,10 +379,91 @@ class SaleOrder(models.Model):
# raise UserError("PO harus di Cancel dahulu")
self.approval_status = False
+ self.due_id = False
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
+
+ if self.due_id and self.due_id.is_approve == False:
+ raise UserError('Document Over Due Yang Anda Buat Belum Di Approve')
+
+ if not self.env.user.is_leader and not self.env.user.is_sales_manager:
+ query = [
+ ('partner_id', '=', parent_id),
+ ('state', '=', 'posted'),
+ ('move_type', '=', 'out_invoice'),
+ ('amount_residual_signed', '>', 0)
+ ]
+ invoices = self.env['account.move'].search(query, order='invoice_date')
+ due_extension = self.env['due.extension'].create([{
+ 'partner_id': parent_id,
+ 'day_extension': '3',
+ 'order_id': self.id,
+ }])
+ due_extension.generate_due_line()
+ self.due_id = due_extension.id
+ if len(self.due_id.due_line) > 0:
+ return True
+ else:
+ due_extension.unlink()
+ return False
+
+ def _notification_margin_leader(self):
+ if self.total_percent_margin <= 15 and not self.env.user.is_leader:
+ return True
+ else:
+ return False
+
+ def _notification_margin_manager(self):
+ if self.total_percent_margin <= 22 and not self.env.user.is_leader and not self.env.user.is_sales_manager:
+ return True
+ else:
+ return False
+
+ def _notification_has_unapprove_due(self):
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'title': 'Notification',
+ 'message': 'Ada Invoice Yang Sudah Over Due, Silahkan Memperbarui Over Due di Due Extension',
+ 'next': {'type': 'ir.actions.act_window_close'},
+ }
+ }
+
+ def _notification_has_margin_leader(self):
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'title': 'Notification',
+ 'message': 'SO Harus Di Approve Oleh Pimpinan',
+ 'next': {'type': 'ir.actions.act_window_close'},
+ }
+ }
+
+ def _notification_has_margin_manager(self):
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'title': 'Notification',
+ 'message': 'SO Harus Di Approve Oleh Sales Manager',
+ 'next': {'type': 'ir.actions.act_window_close'},
+ }
+ }
+
+ def _set_sppkp_npwp_contact(self):
+ parent_id = self.partner_id.parent_id
+ parent_id = parent_id if parent_id else self.partner_id
+ parent_id.customer_type = self.customer_type
+ parent_id.npwp = self.npwp
+ parent_id.sppkp = self.sppkp
+
def action_confirm(self):
- res = super(SaleOrder, self).action_confirm()
for order in self:
if order.warehouse_id.id != 8: #GD Bandengan
raise UserError('Gudang harus Bandengan')
@@ -372,16 +482,20 @@ class SaleOrder(models.Model):
raise UserError(_('Tidak bisa Confirm menggunakan Produk Sementara'))
if not line.vendor_id or not line.purchase_price or not line.purchase_tax_id:
raise UserError(_('Isi Vendor, Harga Beli, dan Tax sebelum Request Approval'))
- if order.total_percent_margin <= 15 and not self.env.user.is_leader:
- raise UserError("Harus diapprove oleh Pimpinan")
- elif order.total_percent_margin <= 22 and not self.env.user.is_leader and not self.env.user.is_sales_manager:
- raise UserError("Harus diapprove oleh Manager")
- elif order._have_outstanding_invoices() and not self.env.user.is_leader and not self.env.user.is_sales_manager:
- raise UserError("Ada invoice due date, harus diapprove oleh Manager")
+
+ if order.validate_partner_invoice_due():
+ return self._notification_has_unapprove_due()
+
+ if order._notification_margin_leader():
+ return self._notification_has_margin_leader()
+ elif order._notification_margin_manager():
+ return self._notification_has_margin_manager()
else:
order.approval_status = 'approved'
- order.calculate_line_no()
+ order._set_sppkp_npwp_contact()
+ order.calculate_line_no()
+ res = super(SaleOrder, self).action_confirm()
return res
def _have_outstanding_invoices(self):
@@ -462,7 +576,7 @@ class SaleOrderLine(models.Model):
'res.partner', string='Vendor', readonly=True,
states={'draft': [('readonly', False)], 'sent': [('readonly', False)]},
change_default=True, index=True, tracking=1,
- domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", )
+ domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]",)
purchase_price = fields.Float('Purchase', required=True, digits='Product Price', default=0.0)
purchase_tax_id = fields.Many2one('account.tax', string='Tax',
domain=['|', ('active', '=', False), ('active', '=', True)])
@@ -470,6 +584,23 @@ class SaleOrderLine(models.Model):
fee_third_party_line = fields.Float('FeeThirdPartyLine', compute='compute_fee_third_party_line', default=0)
line_no = fields.Integer('No', default=0, copy=False)
note_procurement = fields.Char(string='Note', help="Harap diisi jika ada keterangan tambahan dari Procurement, agar dapat dimonitoring")
+ vendor_subtotal = fields.Float(string='Vendor Subtotal', compute="_compute_vendor_subtotal")
+
+ def _compute_vendor_subtotal(self):
+ for line in self:
+ if line.purchase_price > 0 and line.product_uom_qty > 0:
+ # product = line.product_id
+
+ # if product:
+ # vendor_price = line.purchase_price
+ # if line.purchase_tax_id.price_include:
+ # vendor_price = line.purchase_price
+ # else:
+ # vendor_price = line.purchase_price + (line.purchase_price*11/100)
+ subtotal = line.purchase_price * line.product_uom_qty
+ line.vendor_subtotal = subtotal
+ else:
+ line.vendor_subtotal = 0
def compute_item_margin(self):
for line in self:
@@ -530,6 +661,7 @@ class SaleOrderLine(models.Model):
[('product_id', '=', self.product_id.id)], limit=1, order='product_price ASC')
line.vendor_id = purchase_price.vendor_id
line.tax_id = line.order_id.sales_tax_id
+ line.purchase_price = purchase_price.product_price
def compute_delivery_amt_line(self):
for line in self:
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index a14e71a3..2ddb5f75 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -298,14 +298,14 @@ class StockPicking(models.Model):
# continue
# raise UserError('Sudah pernah dikirim kalender')
- if self.picking_type_id.code == 'outgoing':
- for line in self.move_line_ids_without_package:
- if line.move_id.sale_line_id.qty_delivered + line.qty_done > line.move_id.sale_line_id.product_uom_qty:
- raise UserError("Qty Delivered akan lebih dari Qty SO")
- elif self.picking_type_id.code == 'incoming':
- for line in self.move_ids_without_package:
- if line.purchase_line_id.qty_received + line.quantity_done > line.purchase_line_id.product_qty:
- raise UserError('Qty Received akan lebih dari Qty PO')
+ # if self.picking_type_id.code == 'outgoing':
+ # for line in self.move_line_ids_without_package:
+ # if line.move_id.sale_line_id.qty_delivered + line.qty_done > line.move_id.sale_line_id.product_uom_qty:
+ # raise UserError("Qty Delivered akan lebih dari Qty SO")
+ # elif self.picking_type_id.code == 'incoming':
+ # for line in self.move_ids_without_package:
+ # if line.purchase_line_id.qty_received + line.quantity_done > line.purchase_line_id.product_qty:
+ # raise UserError('Qty Received akan lebih dari Qty PO')
if self.is_internal_use:
self.approval_status = 'approved'
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index d809f3c4..a470fa8f 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -1,4 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_due_extension,access.due.extension,model_due_extension,,1,1,1,1
access_x_banner_category,access.x.banner.category,model_x_banner_category,,1,1,1,1
access_x_banner_banner,access.x.banner.banner,model_x_banner_banner,,1,1,1,1
access_x_biaya_kirim,access.x.biaya.kirim,model_x_biaya_kirim,,1,1,1,1
@@ -14,6 +15,7 @@ access_delivery_order,access.delivery.order,model_delivery_order,,1,1,1,1
access_delivery_order_line,access.delivery.order.line,model_delivery_order_line,,1,1,1,1
access_dunning_run,access.dunning.run,model_dunning_run,,1,1,1,1
access_dunning_run_line,access.dunning.run.line,model_dunning_run_line,,1,1,1,1
+access_due_extension_line,access.due.extension.line,model_due_extension_line,,1,1,1,1
access_website_user_cart,access.website.user.cart,model_website_user_cart,,1,1,1,1
access_website_user_wishlist,access.website.user.wishlist,model_website_user_wishlist,,1,1,1,1
access_website_brand_homepage,access.website.brand.homepage,model_website_brand_homepage,,1,1,1,1
diff --git a/indoteknik_custom/views/account_move_views.xml b/indoteknik_custom/views/account_move_views.xml
new file mode 100644
index 00000000..983fbd5a
--- /dev/null
+++ b/indoteknik_custom/views/account_move_views.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<odoo>
+ <record id="due_extension_tree" model="ir.ui.view">
+ <field name="name">due.extension.tree</field>
+ <field name="model">due.extension</field>
+ <field name="arch" type="xml">
+ <tree create="false">
+ <field name="number"/>
+ <field name="partner_id"/>
+ <field name="day_extension"/>
+ <field name="description"/>
+ <field name="approval_status"/>
+ <field name="is_approve"/>
+ </tree>
+ </field>
+ </record>
+
+ <record id="due_extension_line_tree" model="ir.ui.view">
+ <field name="name">due.extension.line.tree</field>
+ <field name="model">due.extension.line</field>
+ <field name="arch" type="xml">
+ <tree>
+ <field name="partner_id"/>
+ <field name="invoice_id"/>
+ <field name="date_invoice"/>
+ <field name="due_date"/>
+ <field name="day_to_due"/>
+ <field name="efaktur_id"/>
+ <field name="reference"/>
+ <field name="total_amt"/>
+ <field name="open_amt"/>
+ </tree>
+ </field>
+ </record>
+
+<record id="due_extension_form" model="ir.ui.view">
+ <field name="name">due.extension.form</field>
+ <field name="model">due.extension</field>
+ <field name="arch" type="xml">
+ <form create="false">
+ <header>
+ <button name="approve_new_due"
+ string="Approve"
+ type="object"
+ />
+ <button name="due_extension_approval"
+ string="Ask Approval"
+ type="object"
+ />
+ <button name="due_extension_cancel"
+ string="Cancel"
+ type="object"
+ />
+ </header>
+ <sheet>
+ <group>
+ <group>
+ <field name="partner_id" readonly="1"/>
+ <field name="day_extension" attrs="{'readonly': [('is_approve', '=', True)]}"/>
+ </group>
+ <group>
+ <field name="is_approve" readonly="1"/>
+ <field name="order_id" readonly="1"/>
+ <field name="counter" readonly="1"/>
+ <field name="approval_status" readonly="1"/>
+ </group>
+ </group>
+ <group>
+ <field name="description" attrs="{'readonly': [('approval_status', '=', 'approved')]}"/>
+ </group>
+ <notebook>
+ <page string="Invoices">
+ <field name="due_line" attrs="{'readonly': [('is_approve', '=', True)]}"/>
+ </page>
+ </notebook>
+ </sheet>
+ <div class="oe_chatter">
+ <field name="message_follower_ids" widget="mail_followers"/>
+ <field name="message_ids" widget="mail_thread"/>
+ </div>
+ </form>
+ </field>
+</record>
+
+ <record id="due_extension_action" model="ir.actions.act_window">
+ <field name="name">Due Extension</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">due.extension</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
+ <menuitem
+ id="menu_due_extension"
+ name="Due Extension"
+ parent="sale.product_menu_catalog"
+ sequence="4"
+ action="due_extension_action"
+ />
+ <menuitem id="menu_due_extension" name="Due Extension"
+ parent="account.menu_finance_receivables"
+ action="due_extension_action"
+ sequence="100"
+ />
+</odoo>
diff --git a/indoteknik_custom/views/delivery_order.xml b/indoteknik_custom/views/delivery_order.xml
index 29ca7365..0b2fd576 100644
--- a/indoteknik_custom/views/delivery_order.xml
+++ b/indoteknik_custom/views/delivery_order.xml
@@ -21,6 +21,7 @@
<field name="arrival_date" readonly="1"/>
<field name="carrier_id" readonly="1"/>
<field name="tracking_no"/>
+ <field name="partner_id" readonly="1"/>
</tree>
</field>
</sheet>
diff --git a/indoteknik_custom/views/ir_sequence.xml b/indoteknik_custom/views/ir_sequence.xml
index 9af85408..a8348772 100644
--- a/indoteknik_custom/views/ir_sequence.xml
+++ b/indoteknik_custom/views/ir_sequence.xml
@@ -31,6 +31,16 @@
<field name="number_increment">1</field>
</record>
+ <record id="sequence_due_extension" model="ir.sequence">
+ <field name="name">Due Extension</field>
+ <field name="code">due.extension</field>
+ <field name="active">TRUE</field>
+ <field name="prefix">DE/%(year)s/</field>
+ <field name="padding">5</field>
+ <field name="number_next">1</field>
+ <field name="number_increment">1</field>
+ </record>
+
<record id="sequence_requisition" model="ir.sequence">
<field name="name">Requisition</field>
<field name="code">requisition</field>
diff --git a/indoteknik_custom/views/purchase_order.xml b/indoteknik_custom/views/purchase_order.xml
index 5b0c99ef..4efa8cf4 100755
--- a/indoteknik_custom/views/purchase_order.xml
+++ b/indoteknik_custom/views/purchase_order.xml
@@ -42,6 +42,11 @@
<field name="total_so_margin"/>
<field name="total_percent_margin"/>
<field name="total_so_percent_margin"/>
+ <button name="re_calculate"
+ string="Re Calculate"
+ type="object"
+ attrs="{'invisible': [('approval_status', '=', 'approved')]}"
+ />
</field>
<field name="product_id" position="before">
<field name="line_no" attrs="{'readonly': 1}" optional="hide"/>
@@ -59,6 +64,8 @@
</page>
<field name="fiscal_position_id" position="after">
<field name="note_description"/>
+ <field name="total_so_percent_margin"/>
+
</field>
</field>
</record>
diff --git a/indoteknik_custom/views/res_partner.xml b/indoteknik_custom/views/res_partner.xml
index a9372da0..d609fdd5 100644
--- a/indoteknik_custom/views/res_partner.xml
+++ b/indoteknik_custom/views/res_partner.xml
@@ -6,13 +6,18 @@
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
- <field name="vat" position="after">
+ <field name="npwp" position="after">
+ <field name="sppkp"/>
+ <field name="counter"/>
<field name="reference_number"/>
</field>
<field name="industry_id" position="after">
<field name="company_type_id"/>
<field name="group_partner_id"/>
</field>
+ <field name="npwp" position="before">
+ <field name="customer_type"/>
+ </field>
</field>
</record>
</data>
diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml
index 85f687c1..70e3392f 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -27,6 +27,12 @@
<field name="fee_third_party"/>
<field name="total_percent_margin"/>
</field>
+ <field name="analytic_account_id" position="after">
+ <field name="customer_type" attrs="{'required': ['|', ('create_date', '&gt;', '2023-06-28'), ('create_date', '=', False)]}"/>
+ <field name="npwp" placeholder='99.999.999.9-999.999' attrs="{'required': ['|', ('create_date', '&gt;', '2023-06-28'), ('create_date', '=', False)]}"/>
+ <field name="sppkp" attrs="{'invisible': [('customer_type','!=','pkp')], 'required': [('customer_type', '=', 'pkp')]}"/>
+ <field name="due_id" readonly="1"/>
+ </field>
<field name="partner_shipping_id" position="after">
<field name="real_shipping_id"/>
<field name="approval_status" />
@@ -63,6 +69,7 @@
<field name="purchase_tax_id" attrs="{'readonly': [('parent.approval_status', '!=', False)]}" domain="[('type_tax_use','=','purchase')]"/>
<field name="item_percent_margin"/>
<field name="note_procurement" optional="hide"/>
+ <field name="vendor_subtotal" optional="hide"/>
</xpath>
<xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='product_id']" position="before">
<field name="line_no" readonly="1" optional="hide"/>