summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAzka Nathan <darizkyfaz@gmail.com>2023-06-23 14:12:49 +0700
committerAzka Nathan <darizkyfaz@gmail.com>2023-06-23 14:12:49 +0700
commitfb8abc000707a2b8ba1fb0d16c1d8cbbd640ea34 (patch)
treeb78521ab23e1e44575618e5b60e407642a785b36
parente595c9ce8de2eb8c778b998cef58b2d85c29a6a7 (diff)
Fiture Over Due Limit
-rwxr-xr-xindoteknik_custom/__manifest__.py1
-rwxr-xr-xindoteknik_custom/models/__init__.py1
-rw-r--r--indoteknik_custom/models/account_move_due_extension.py121
-rwxr-xr-xindoteknik_custom/models/sale_order.py120
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv2
-rw-r--r--indoteknik_custom/views/account_move_views.xml82
-rw-r--r--indoteknik_custom/views/ir_sequence.xml10
-rwxr-xr-xindoteknik_custom/views/sale_order.xml3
8 files changed, 315 insertions, 25 deletions
diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py
index eaa5390a..79f6e195 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 9764e0c0..9d0f8d47 100755
--- a/indoteknik_custom/models/__init__.py
+++ b/indoteknik_custom/models/__init__.py
@@ -63,3 +63,4 @@ from . import procurement_monitoring_detail
from . import brand_vendor
from . import manufacturing
from . import requisition
+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..1de34408
--- /dev/null
+++ b/indoteknik_custom/models/account_move_due_extension.py
@@ -0,0 +1,121 @@
+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"
+ _rec_name = 'number'
+
+ number = fields.Char(string='Document No', index=True, copy=False, readonly=True)
+ partner_id = fields.Many2one('res.partner', string="Customer")
+ 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")
+ is_approve = fields.Boolean(string="Is Approve", readonly=True)
+ 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')
+
+ @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 approve_new_due(self):
+ if self.env.user.is_accounting:
+ if not self.day_extension:
+ raise UserError('Day Extension is not set.')
+ if not self.due_line:
+ raise UserError('Tidak ada data di due line.')
+
+ self.is_approve = True
+
+ 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.action_confirm()
+ else:
+ raise UserError('Hanya Finance Yang Bisa Approve')
+
+ def generate_due_line(self):
+ if self.is_approve:
+ raise UserError('Sudah di approve, tidak bisa digenerate ulang')
+ if self.due_line:
+ raise UserError('Harus hapus semua line jika ingin generate ulang')
+ if self.partner_id.parent_id:
+ raise UserError('Harus pilih parent company')
+
+
+ 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)
+
+class DueExtensionLine(models.Model):
+ _name = 'due.extension.line'
+ _description = 'Due Extension Line'
+ _order = 'due_id, id'
+
+ due_id = fields.Many2one('due.extension', string='Dunning 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')
+ 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
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index e99876c2..d531c869 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -78,6 +78,7 @@ 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)
def generate_payment_link_midtrans_sales_order(self):
# midtrans_url = 'https://app.sandbox.midtrans.com/snap/v1/transactions' # dev - sandbox
@@ -282,18 +283,10 @@ class SaleOrder(models.Model):
def sale_order_approve(self):
# raise UserError("Bisa langsung Confirm")
self.check_due()
- invoices = self.env['account.move'].search([
- ('partner_id', '=', self.partner_id.id),
- ('invoice_day_to_due', '<', 0)
- ])
- due_extension_obj = self.env['due.extension']
+ parent_id = self.partner_id.parent_id.id
+ parent_id = parent_id if parent_id else self.partner_id.id
+
for order in self:
- for invoice in invoices:
- if invoice.invoice_day_to_due < 0:
- value = {
- 'invoice_id': invoice.id
- }
- due_extension_obj.create(value)
if order.warehouse_id.id != 8: #GD Bandengan
raise UserError('Gudang harus Bandengan')
if order.state == 'cancel' or order.state == 'done' or order.state == 'sale':
@@ -329,14 +322,16 @@ class SaleOrder(models.Model):
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:
+ return self._notification_has_margin_leader()
+ elif order._notification_margin_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:
- order.approval_status = 'pengajuan1'
- elif invoice.invoice_day_to_due < 0:
- raise UserError("Anda Harus Memperbarui Due Date di Due Extension")
+ return self._notification_has_margin_manager()
else:
raise UserError("Bisa langsung Confirm")
@@ -354,9 +349,81 @@ class SaleOrder(models.Model):
self.approval_status = 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 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')
@@ -375,16 +442,19 @@ 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.calculate_line_no()
+ res = super(SaleOrder, self).action_confirm()
return res
def _have_outstanding_invoices(self):
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index 26e852f1..df820053 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..1ff7f3aa
--- /dev/null
+++ b/indoteknik_custom/views/account_move_views.xml
@@ -0,0 +1,82 @@
+<?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="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"
+ class="mr-2 oe_highlight oe_edit_only"
+ attrs="{'invisible': [('is_approve', '=', True)]}"
+ />
+ </header>
+ <sheet>
+ <group>
+ <group>
+ <field name="partner_id" required="1" attrs="{'readonly': [('is_approve', '=', True)]}"/>
+ <field name="day_extension" attrs="{'readonly': [('is_approve', '=', True)]}"/>
+ </group>
+ <group>
+ <field name="is_approve" readonly="1"/>
+ <field name="order_id" readonly="1"/>
+ </group>
+ </group>
+ <notebook>
+ <page string="Invoices">
+ <field name="due_line" attrs="{'readonly': [('is_approve', '=', True)]}"/>
+ </page>
+ </notebook>
+ </sheet>
+ </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"
+ />
+</odoo>
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/sale_order.xml b/indoteknik_custom/views/sale_order.xml
index b160d9b1..222fb057 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -26,6 +26,9 @@
<field name="fee_third_party"/>
<field name="total_percent_margin"/>
</field>
+ <field name="analytic_account_id" position="after">
+ <field name="due_id" readonly="1"/>
+ </field>
<field name="partner_shipping_id" position="after">
<field name="real_shipping_id"/>
<field name="approval_status" />