Browse Source

Oct 22: [UPDT] Module Updated 'base_accounting_kit'

pull/346/head
Cybrosys Technologies 6 months ago
parent
commit
28a4f7ac99
  1. 11
      base_accounting_kit/__manifest__.py
  2. 6
      base_accounting_kit/doc/RELEASE_NOTES.md
  3. 16
      base_accounting_kit/models/account_bank_statement_line.py
  4. 51
      base_accounting_kit/models/account_journal.py
  5. 20
      base_accounting_kit/models/res_company.py
  6. 5
      base_accounting_kit/security/ir.model.access.csv
  7. BIN
      base_accounting_kit/static/description/assets/screenshots/loc3.png
  8. BIN
      base_accounting_kit/static/description/assets/screenshots/loc_1.png
  9. BIN
      base_accounting_kit/static/description/assets/screenshots/loc_2.png
  10. BIN
      base_accounting_kit/static/description/assets/screenshots/rec_1.png
  11. BIN
      base_accounting_kit/static/description/assets/screenshots/rec_2.png
  12. BIN
      base_accounting_kit/static/description/assets/screenshots/rec_3.png
  13. BIN
      base_accounting_kit/static/description/banner.jpg
  14. BIN
      base_accounting_kit/static/description/banner.png
  15. 179
      base_accounting_kit/static/description/index.html
  16. 129
      base_accounting_kit/static/src/js/KanbanController.js
  17. 168
      base_accounting_kit/static/src/js/ListController.js
  18. 79
      base_accounting_kit/static/src/js/bank_reconcile_form_lines_widget.js
  19. 124
      base_accounting_kit/static/src/js/bank_reconcile_form_list_widget.js
  20. 1
      base_accounting_kit/static/src/scss/style.scss
  21. 33
      base_accounting_kit/static/src/xml/bank_rec_widget.xml
  22. 124
      base_accounting_kit/static/src/xml/bank_reconcile_widget.xml
  23. 1
      base_accounting_kit/wizard/__init__.py
  24. 64
      base_accounting_kit/wizard/account_lock_date.py
  25. 46
      base_accounting_kit/wizard/account_lock_date_views.xml

11
base_accounting_kit/__manifest__.py

@ -21,7 +21,7 @@
############################################################################# #############################################################################
{ {
'name': 'Odoo 18 Full Accounting Kit for Community', 'name': 'Odoo 18 Full Accounting Kit for Community',
'version': '18.0.1.0.0', 'version': '18.0.1.0.1',
'category': 'Accounting', 'category': 'Accounting',
'summary': """Odoo 18 Accounting, Odoo 18 Accounting Reports, Odoo18 Accounting, Odoo Accounting, Odoo18 Financial Reports, Odoo18 Asset, Odoo18 Profit and Loss, PDC, Followups, Odoo18, Accounting, Odoo Apps, Reports""", 'summary': """Odoo 18 Accounting, Odoo 18 Accounting Reports, Odoo18 Accounting, Odoo Accounting, Odoo18 Financial Reports, Odoo18 Asset, Odoo18 Profit and Loss, PDC, Followups, Odoo18, Accounting, Odoo Apps, Reports""",
'description': """ Odoo 18 Accounting, The module used to manage the Full 'description': """ Odoo 18 Accounting, The module used to manage the Full
@ -92,15 +92,22 @@
'views/account_bank_statement_views.xml', 'views/account_bank_statement_views.xml',
'views/account_bank_statement_line_views.xml', 'views/account_bank_statement_line_views.xml',
'views/account_payment_view.xml', 'views/account_payment_view.xml',
'wizard/account_lock_date_views.xml',
], ],
'assets': { 'assets': {
'web.assets_backend': [ 'web.assets_backend': [
'base_accounting_kit/static/src/scss/style.scss', 'base_accounting_kit/static/src/scss/style.scss',
'base_accounting_kit/static/src/scss/bank_rec_widget.css', 'base_accounting_kit/static/src/scss/bank_rec_widget.css',
'base_accounting_kit/static/src/js/bank_reconcile_form_list_widget.js',
'base_accounting_kit/static/src/js/KanbanController.js',
'base_accounting_kit/static/src/js/ListController.js',
'base_accounting_kit/static/src/js/bank_reconcile_form_lines_widget.js',
'base_accounting_kit/static/src/xml/bank_rec_widget.xml',
'base_accounting_kit/static/src/xml/bank_reconcile_widget.xml',
] ]
}, },
'license': 'LGPL-3', 'license': 'LGPL-3',
'images': ['static/description/banner.jpg'], 'images': ['static/description/banner.png'],
'installable': True, 'installable': True,
'auto_install': False, 'auto_install': False,
'application': True, 'application': True,

6
base_accounting_kit/doc/RELEASE_NOTES.md

@ -4,3 +4,9 @@
#### Version 18.0.1.0.0 #### Version 18.0.1.0.0
#### ADD #### ADD
- Initial commit for Odoo 18 Full Accounting Kit for Community - Initial commit for Odoo 18 Full Accounting Kit for Community
#### 22.10.2024
#### Version 18.0.1.0.1
#### UPDT
- Added the reconciliation widget and lock dates.

16
base_accounting_kit/models/account_bank_statement_line.py

@ -79,12 +79,20 @@ class AccountBankStatementLine(models.Model):
"""Ensure the current recordset holds a single record and mark it as reconciled.""" """Ensure the current recordset holds a single record and mark it as reconciled."""
self.ensure_one() self.ensure_one()
self.is_reconciled = True self.is_reconciled = True
return {
'type': 'ir.actions.client',
'tag': 'reload',
}
def button_reset(self): def button_reset(self):
"""Reset the current bank statement line if it is in a 'reconciled' state.""" """Reset the current bank statement line if it is in a 'reconciled' state."""
self.ensure_one() self.ensure_one()
if self.bank_state == 'reconciled': if self.bank_state == 'reconciled':
self.action_undo_reconciliation() self.action_undo_reconciliation()
return {
'type': 'ir.actions.client',
'tag': 'reload',
}
def button_to_check(self, async_action=True): def button_to_check(self, async_action=True):
"""Ensure the current recordset holds a single record, validate the bank """Ensure the current recordset holds a single record, validate the bank
@ -93,11 +101,19 @@ class AccountBankStatementLine(models.Model):
if self.bank_state == 'valid': if self.bank_state == 'valid':
self.button_validation(async_action=async_action) self.button_validation(async_action=async_action)
self.move_id.to_check = True self.move_id.to_check = True
return {
'type': 'ir.actions.client',
'tag': 'reload',
}
def button_set_as_checked(self): def button_set_as_checked(self):
"""Mark the associated move as 'not to check' by setting 'to_check' to False.""" """Mark the associated move as 'not to check' by setting 'to_check' to False."""
self.ensure_one() self.ensure_one()
self.move_id.to_check = False self.move_id.to_check = False
return {
'type': 'ir.actions.client',
'tag': 'reload',
}
@api.model @api.model
def get_statement_line(self, record_id): def get_statement_line(self, record_id):

51
base_accounting_kit/models/account_journal.py

@ -55,7 +55,56 @@ class AccountJournal(models.Model):
def action_open_reconcile(self): def action_open_reconcile(self):
"""Open the reconciliation view based on the type of the account journal.""" """Open the reconciliation view based on the type of the account journal."""
self.ensure_one() self.ensure_one()
if self.type in ('bank', 'cash'):
views = [
(self.env.ref(
'base_accounting_kit.account_bank_statement_line_view_kanban').id,
'kanban'),
(self.env.ref(
'base_accounting_kit.account_bank_statement_line_view_tree').id,
'list'), # Include tree view
]
context = {
'default_journal_id': self.id,
'search_default_journal_id': self.id,
}
kanban_first = True
name = None
extra_domain = None
return {
'name': name or _("Bank Reconciliation"),
'type': 'ir.actions.act_window',
'res_model': 'account.bank.statement.line',
'context': context,
'search_view_id': [
self.env.ref(
'base_accounting_kit.account_bank_statement_line_view_search').id,
'search'],
'view_mode': 'kanban,list' if kanban_first else 'list,kanban',
'views': views if kanban_first else views[::-1],
'domain': [('state', '!=', 'cancel')] + (extra_domain or []),
'help': _("""
<p class="o_view_nocontent_smiling_face">
Nothing to do here!
</p>
<p>
No transactions matching your filters were found.
</p>
"""),
}
else:
# Open reconciliation view for customers/suppliers
action_context = {'show_mode_selector': False,
'company_ids': self.mapped('company_id').ids}
if self.type == 'sale':
action_context.update({'mode': 'customers'})
elif self.type == 'purchase':
action_context.update({'mode': 'suppliers'})
return {
'type': 'ir.actions.client',
'tag': 'manual_reconciliation_view',
'context': action_context,
}
def create_cash_statement(self): def create_cash_statement(self):
"""for redirecting in to bank statement lines""" """for redirecting in to bank statement lines"""

20
base_accounting_kit/models/res_company.py

@ -27,14 +27,13 @@ class ResCompany(models.Model):
"""Model for inheriting res_company.""" """Model for inheriting res_company."""
_inherit = "res.company" _inherit = "res.company"
def _validate_fiscalyear_lock(self, values): def _validate_locks(self, values):
"""Validate the fiscal year lock date by checking for unposted entries and unreconciled bank statement lines.""" """Validate the hard lock date by checking for unposted entries and unreconciled bank statement lines."""
if values.get('fiscalyear_lock_date'): if values.get('hard_lock_date'):
draft_entries = self.env['account.move'].search([ draft_entries = self.env['account.move'].search([
('company_id', 'in', self.ids), ('company_id', 'in', self.ids),
('state', '=', 'draft'), ('state', '=', 'draft'),
('date', '<=', values['fiscalyear_lock_date'])]) ('date', '<=', values['hard_lock_date'])])
if draft_entries: if draft_entries:
error_msg = _('There are still unposted entries in the ' error_msg = _('There are still unposted entries in the '
'period you want to lock. You should either post ' 'period you want to lock. You should either post '
@ -53,21 +52,20 @@ class ResCompany(models.Model):
unreconciled_statement_lines = self.env['account.bank.statement.line'].search([ unreconciled_statement_lines = self.env['account.bank.statement.line'].search([
('company_id', 'in', self.ids), ('company_id', 'in', self.ids),
('is_reconciled', '=', False), ('is_reconciled', '=', False),
('date', '<=', values['fiscalyear_lock_date']), ('date', '<=', values['hard_lock_date']),
('move_id.state', 'in', ('draft', 'posted')), ('move_id.state', 'in', ('draft', 'posted')),
]) ])
if unreconciled_statement_lines: if unreconciled_statement_lines:
error_msg = _("There are still unreconciled bank statement lines in the period you want to lock." error_msg = _("There are still unreconciled bank statement lines in the period you want to lock."
"You should either reconcile or delete them.") "You should either reconcile or delete them.")
action_error = { action_error = {
'view_mode': 'list', 'view_mode': 'kanban',
'name': 'Unreconciled Transactions', 'name': 'Unreconciled Transactions',
'res_model': 'account.bank.statement.line', 'res_model': 'account.bank.statement.line',
'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
'domain': [('id', 'in', unreconciled_statement_lines.ids)], 'domain': [('id', 'in', unreconciled_statement_lines.ids)],
'views': [[self.env.ref( 'views': [[self.env.ref(
'base_accounting_kit.view_bank_statement_line_tree').id, 'base_accounting_kit.account_bank_statement_line_view_kanban').id,
'list']] 'kanban']]
} }
raise RedirectWarning(error_msg, action_error, raise RedirectWarning(error_msg, action_error, _('Show Unreconciled Bank Statement Lines'))
_('Show Unreconciled Bank Statement Line'))

5
base_accounting_kit/security/ir.model.access.csv

@ -42,9 +42,6 @@ access_account_common_journal_report,account.common.journal.report,model_account
access_account_account_type,account.account.type,model_account_account_type,account.group_account_user,1,1,1,1 access_account_account_type,account.account.type,model_account_account_type,account.group_account_user,1,1,1,1
access_account_lock_date,access.account.lock.date,model_account_lock_date,account.group_account_user,1,1,1,1
access_account_recurring_entries_line,access.account.recurring.entries.line,model_account_recurring_entries_line,account.group_account_user,1,1,1,1 access_account_recurring_entries_line,access.account.recurring.entries.line,model_account_recurring_entries_line,account.group_account_user,1,1,1,1
access_generate_recurring_entries,generate.recurring.entries.user,model_account_recurring_payments,account.group_account_user,1,1,1,1 access_generate_recurring_entries,generate.recurring.entries.user,model_account_recurring_payments,account.group_account_user,1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
42 access_generate_recurring_entries generate.recurring.entries.user model_account_recurring_payments account.group_account_user 1 1 1 1
43
44
45
46
47

BIN
base_accounting_kit/static/description/assets/screenshots/loc3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
base_accounting_kit/static/description/assets/screenshots/loc_1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
base_accounting_kit/static/description/assets/screenshots/loc_2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
base_accounting_kit/static/description/assets/screenshots/rec_1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
base_accounting_kit/static/description/assets/screenshots/rec_2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
base_accounting_kit/static/description/assets/screenshots/rec_3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

BIN
base_accounting_kit/static/description/banner.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 767 KiB

BIN
base_accounting_kit/static/description/banner.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

179
base_accounting_kit/static/description/index.html

@ -126,7 +126,7 @@
font-size: 46px; font-size: 46px;
font-weight: 700; font-weight: 700;
line-height: normal; line-height: normal;
">Odoo 18 Full Accounting Kit for Community</span> ">Odoo 18 Full Accounting Kit</span>
</h1> </h1>
</div> </div>
<div class="col-lg-12 d-flex justify-content-center align-items-center" <div class="col-lg-12 d-flex justify-content-center align-items-center"
@ -336,7 +336,7 @@
</p> </p>
</div> </div>
</div> </div>
<div class="col-lg-4"> <div class="col-lg-4">
<div class="mb-4 d-flex flex-column justify-content-center gap-3" <div class="mb-4 d-flex flex-column justify-content-center gap-3"
style="border-radius: 12px; style="border-radius: 12px;
border: 1px solid #B6BCCD; border: 1px solid #B6BCCD;
@ -357,7 +357,48 @@
</p> </p>
</div> </div>
</div> </div>
<div class="col-lg-4">
<div class="mb-4 d-flex flex-column justify-content-center gap-3"
style="border-radius: 12px;
border: 1px solid #B6BCCD;
background: #FFF;padding:32px ">
<div class="d-flex justify-content-center align-items-center"
style="background-color:#7847D9; border-radius:8px !important; height:42px; width:42px">
<img src="./assets/icons/feature-icon.svg"
class="img-responsive" height="26px"
width="26px">
</div>
<h5 class="m-0"
style="color:#000 !important; font-weight:bold">
Reconciliation Widget.
</h5>
<p class="m-0"
style="font-size:0.9rem; color:var(--text-color-light); font-size: 16px; font-weight: 400;">
In the Account Dashboard we can reconcile by clicking the button Reconcile.
</p>
</div>
</div>
<div class="col-lg-4">
<div class="mb-4 d-flex flex-column justify-content-center gap-3"
style="border-radius: 12px;
border: 1px solid #B6BCCD;
background: #FFF;padding:32px ">
<div class="d-flex justify-content-center align-items-center"
style="background-color:#7847D9; border-radius:8px !important; height:42px; width:42px">
<img src="./assets/icons/feature-icon.svg"
class="img-responsive" height="26px"
width="26px">
</div>
<h5 class="m-0"
style="color:#000 !important; font-weight:bold">
Lock Dates.
</h5>
<p class="m-0"
style="font-size:0.9rem; color:var(--text-color-light); font-size: 16px; font-weight: 400;">
In the Lock Dates wizard we can set the different Lock Dates.
</p>
</div>
</div>
</div> </div>
</div> </div>
<!--code --> <!--code -->
@ -366,7 +407,7 @@
<div class="wrapper-info" <div class="wrapper-info"
style="display: flex; flex-direction: column; gap: 20px;"> style="display: flex; flex-direction: column; gap: 20px;">
<span class="wrapper-subtitle" <span class="wrapper-subtitle"
style="font-size: 40px; font-weight: 700; color: #fff;line-height: 60px; text-transform: capitalize; width: 450px;">Odoo 18 Full Accounting Kit for Community</span> style="font-size: 40px; font-weight: 700; color: #fff;line-height: 60px; text-transform: capitalize; width: 450px;">Odoo 18 Full Accounting Kit</span>
<h3 class="wrapper-details" <h3 class="wrapper-details"
style="font-size: 20px; font-weight: 400; color: #fff; line-height: 32px; "> style="font-size: 20px; font-weight: 400; color: #fff; line-height: 32px; ">
Are you ready to make your business more Are you ready to make your business more
@ -605,9 +646,7 @@
<div class="col-md-12"> <div class="col-md-12">
<h1 style="font-weight:bold; font-size:calc(1.1rem + 1vw); line-height:120%; text-align:center; text-transform:capitalize; font-size: 40px; <h1 style="font-weight:bold; font-size:calc(1.1rem + 1vw); line-height:120%; text-align:center; text-transform:capitalize; font-size: 40px;
font-weight: 700;"> font-weight: 700;">
<span style="color:#121212; font-size:calc(1.1rem + 1vw)"> Manage <span style="color:#121212; font-size:calc(1.1rem + 1vw)"> Manage</span>
</span>
<span style="color: var(--primary-color); font-size:calc(1.1rem + 1vw)"> Post dated checks.</span> <span style="color: var(--primary-color); font-size:calc(1.1rem + 1vw)"> Post dated checks.</span>
</h1> </h1>
</div> </div>
@ -629,6 +668,86 @@
</div> </div>
</div> </div>
<div class="position-relative mb-4"
style="border-radius:10px; background-color:#f4f4f4">
<div class="p-md-5 p-3 position-relative">
<div class="row">
<div class="col-md-12">
<h1 style="font-weight:bold; font-size:calc(1.1rem + 1vw); line-height:120%; text-align:center; text-transform:capitalize; font-size: 40px;
font-weight: 700;">
<span style="color:#121212; font-size:calc(1.1rem + 1vw)"> Reconciliation</span>
<span style="color: var(--primary-color); font-size:calc(1.1rem + 1vw)"> Widget.</span>
</h1>
</div>
<!-- <div class="col-md-12 mb-4">-->
<!-- <p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:var(&#45;&#45;text-color-light)">-->
<!-- Can reconcile the entries.-->
<!-- </p>-->
<!-- </div>-->
<div class="col-md-12 text-center">
<div class="d-inline-block p-3 shadow-sm"
style="background-color:#fff; border-radius:10px">
<img alt="" class="img-fluid"
loading="lazy"
src="./assets/screenshots/rec_1.png"
style="min-height: 1px;">
</div>
<div class="d-inline-block p-3 shadow-sm"
style="background-color:#fff; border-radius:10px;margin-top:10px;">
<img alt="" class="img-fluid"
loading="lazy"
src="./assets/screenshots/rec_2.png"
style="min-height: 1px;">
</div>
<div class="d-inline-block p-3 shadow-sm"
style="background-color:#fff; border-radius:10px;margin-top:10px;">
<img alt="" class="img-fluid"
loading="lazy"
src="./assets/screenshots/rec_3.png"
style="min-height: 1px;">
</div>
</div>
</div>
</div>
</div>
<div class="position-relative mb-4"
style="border-radius:10px; background-color:#f4f4f4">
<div class="p-md-5 p-3 position-relative">
<div class="row">
<div class="col-md-12">
<h1 style="font-weight:bold; font-size:calc(1.1rem + 1vw); line-height:120%; text-align:center; text-transform:capitalize; font-size: 40px;
font-weight: 700;">
<span style="color:#121212; font-size:calc(1.1rem + 1vw)"> Lock</span>
<span style="color: var(--primary-color); font-size:calc(1.1rem + 1vw)"> Dates.</span>
</h1>
</div>
<div class="col-md-12 text-center">
<div class="d-inline-block p-3 shadow-sm"
style="background-color:#fff; border-radius:10px">
<img alt="" class="img-fluid"
loading="lazy"
src="./assets/screenshots/loc_1.png"
style="min-height: 1px;">
</div>
<div class="d-inline-block p-3 shadow-sm"
style="background-color:#fff; border-radius:10px;margin-top:10px;">
<img alt="" class="img-fluid"
loading="lazy"
src="./assets/screenshots/loc_2.png"
style="min-height: 1px;">
</div>
<div class="d-inline-block p-3 shadow-sm"
style="background-color:#fff; border-radius:10px;margin-top:10px;">
<img alt="" class="img-fluid"
loading="lazy"
src="./assets/screenshots/loc3.png"
style="min-height: 1px;">
</div>
</div>
</div>
</div>
</div>
<div class="position-relative mb-4" <div class="position-relative mb-4"
style="border-radius:10px; background-color:#f4f4f4"> style="border-radius:10px; background-color:#f4f4f4">
<div class="p-md-5 p-3 position-relative"> <div class="p-md-5 p-3 position-relative">
@ -1103,7 +1222,7 @@
</div> </div>
</div> </div>
<div class="col-md-6 col-sm-12 p-3"> <div class="col-md-6 col-sm-12 p-3">
<div class="d-flex flex-column align-items-start h-100" <div class="d-flex flex-column align-items-start h-100"
style="padding:30px; border-radius:12px; background-color:#faf8ff"> style="padding:30px; border-radius:12px; background-color:#faf8ff">
<div class="d-flex align-items-center justify-content-center"> <div class="d-flex align-items-center justify-content-center">
@ -1133,6 +1252,21 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-6 col-sm-12 p-3">
<div class="d-flex flex-column align-items-start h-100"
style="padding:30px; border-radius:12px; background-color:#faf8ff">
<div class="d-flex align-items-center justify-content-center">
<div class="d-flex align-items-center justify-content-center "
style="width:36px; height:36px; border-radius:50%; background-color:#7847D9 ; margin-right:10px">
<i class="fa fa-star "
style="color:#fff; font-size:14px"></i>
</div>
<p style="color:#1A202C; font-weight:600; font-size:1.2rem; margin-bottom:2px">
Reconciliation Widget.
</p>
</div>
</div>
</div>
</div> </div>
</div> </div>
@ -1244,6 +1378,35 @@
class="tab-pane fade show" id="releases" class="tab-pane fade show" id="releases"
role="tabpanel"> role="tabpanel">
<!-- Release Notes --> <!-- Release Notes -->
<div class="row pt-5 m-0">
<div class="col-md-3">
<h4 style="font-size:16px; font-weight:600; color:#514F4F; margin:0; line-height:26px;">
Latest Release 18.0.1.0.1
</h4>
<span style="font-size:14px; color:#7A7979; display:block; margin-bottom:20px;">
22nd October, 2024
</span>
</div>
<div class="col-md-8">
<div style="padding:0 0 40px">
<div style="margin:0 0 10px">
<div style="display:inline-block; padding:0px 8px; color:#514F4F; background-color:#FFD8D8; border-radius:20px">
Updt
</div>
</div>
<div class="d-flex m-0"
style="color:#7A7979;">
<ul class="pl-3 mb-0">
<li>
Added reconciliation widget and lock date
</li>
</ul>
</div>
</div>
<div style="padding:0 0 0; border-bottom:1px solid #E3E3E3">
</div>
</div>
</div>
<div class="row pt-5 m-0"> <div class="row pt-5 m-0">
<div class="col-md-3"> <div class="col-md-3">
<h4 style="font-size:16px; font-weight:600; color:#514F4F; margin:0; line-height:26px;"> <h4 style="font-size:16px; font-weight:600; color:#514F4F; margin:0; line-height:26px;">

129
base_accounting_kit/static/src/js/KanbanController.js

@ -0,0 +1,129 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { useService } from "@web/core/utils/hooks";
import { View } from "@web/views/view";
import { kanbanView } from "@web/views/kanban/kanban_view";
import { KanbanController } from "@web/views/kanban/kanban_controller";
import { KanbanRenderer } from "@web/views/kanban/kanban_renderer";
import { KanbanRecord } from "@web/views/kanban/kanban_record";
const { useState } = owl;
class CustomKanbanController extends KanbanController {
async setup(){
super.setup()
this.state = useState({
selectedStLineId: null,
linesWidgetData: null,
moveLineData: null,
});
this.action = useService("action")
this.orm = useService("orm")
const o_bank_reconcile_status_buttons_aside_left = document.getElementsByClassName("o_bank_reconcile_status_buttons_aside_left")
}
async openRecord(record, mode) {
this.state.moveLineData = null;
this.state.viewID = await this.orm.call('res.config.settings', 'get_view_id', [])
await this.mountStLine(record.resId);
const statementRecord = document.querySelectorAll('.o_bank_reconcile_st_line_kanban_card');
statementRecord.forEach(line => {
line.addEventListener('click', async (event) => {
// Remove 'div-added' class and its child divs from all elements
statementRecord.forEach(item => {
item.classList.remove('div-added');
const childDiv = item.querySelector('.new-div');
if (childDiv) {
item.removeChild(childDiv);
}
});
// Add 'div-added' class and new div to the clicked record
if (!line.classList.contains('div-added')) {
const newDiv = document.createElement('div');
newDiv.classList.add('new-div'); // Add a class to identify the new div
line.classList.add('div-added');
line.appendChild(newDiv);
}
});
});
}
async mountStLine(stLineId){
const currentStLineId = this.state.selectedStLineId;
if (currentStLineId !== stLineId) {
this.state.selectedStLineId = stLineId; // Update selected ST Line ID
try {
const data = await this.orm.call("account.bank.statement.line", "get_statement_line", [stLineId]);
this.state.linesWidgetData = data;
} catch (error) {
console.error("Error fetching statement line data:", error);
}
try {
const data = await this.orm.call('account.bank.statement.line', 'read', [[stLineId]], { fields: ['lines_widget_json'] });
if (data && data.length > 0 && data[0].lines_widget_json) {
const parsedData = JSON.parse(data[0].lines_widget_json);
const moveIdMatch = parsedData.move_id.match(/\((\d+),\)/);
parsedData.numeric_move_id = moveIdMatch ? parseInt(moveIdMatch[1]) : null;
this.state.moveLineData = parsedData;
} else {
console.warn("No lines_widget_json found for selected statement line.");
}
} catch (error) {
console.error("Error reading statement line:", error);
}
}
}
get prepareFormPropsBankReconcile(){
if (!this.state.selectedStLineId) {
return null; // or some default props
}
return {
type: "form",
viewId: this.state.viewID,
context: {
default_st_line_id: this.state.selectedStLineId,
default_lines_widget: this.state.linesWidgetData || null,
default_move_line: this.state.moveLineData || null,
},
display: { controlPanel: false, noBreadcrumbs: true},
mode: "edit",
resModel: "account.bank.statement.line",
resId: this.state.selectedStLineId,
}
}
}
CustomKanbanController.components = {
...CustomKanbanController.components, View }
CustomKanbanController.template = "base_accounting_kit.CustomKanbanView";
export class BankCustomKanbanRenderer extends KanbanRenderer {
setup(){
super.setup();
}
}
export class BankReconcileKanbanRecord extends KanbanRecord {
setup(){
super.setup();
this.state=useState({
Statement_record:{}
})
}
}
BankReconcileKanbanRecord.template = "base_accounting_kit.BankReconcileKanbanRecord";
BankCustomKanbanRenderer.components = {
...KanbanRenderer.components,
KanbanRecord: BankReconcileKanbanRecord,
}
BankCustomKanbanRenderer.template = "base_accounting_kit.BankRecKanbanRenderer";
export const customKanbanView = {
...kanbanView,
Controller: CustomKanbanController,
Renderer: BankCustomKanbanRenderer,
searchMenuTypes: ["filter"],
};
// Register it to the views registry
registry.category("views").add("custom_kanban", customKanbanView);

168
base_accounting_kit/static/src/js/ListController.js

@ -0,0 +1,168 @@
/** @odoo-module **/
import { registry } from '@web/core/registry';
import { ListController } from "@web/views/list/list_controller";
import { listView } from "@web/views/list/list_view";
import { useState, useRef } from "@odoo/owl";
import { useListener, useService} from "@web/core/utils/hooks";
export class AccountMoveLineListController extends ListController {
constructor() {
super(...arguments);
this.resIdList = [];
}
setup(){
super.setup();
this.state = useState({ selectedRecordId: null ,
selectedRecordIds: [],});
this.action = useService("action")
this.orm = useService("orm")
}
async openRecord(record) {
const kanban_row = this.__owl__.bdom.parentEl.ownerDocument.querySelector(`tr[data-id]`);
const data_id = parseInt(kanban_row.getAttribute('data-id'))
var data = await this.orm.call('account.bank.statement.line',
'update_match_row_data',
[record.resId])
await this.orm.call('account.bank.statement.line', 'write', [[data_id], { lines_widget_json: JSON.stringify(data) }]);
const rowSelector = this.__owl__.bdom.parentEl.querySelector(`tr[data-id='${record.id}']`)
if (!record.clickCount) {
record.clickCount = true
rowSelector.style.backgroundColor = "#d1ecf1";
} else {
// Set the default background color here
record.clickCount = false;
rowSelector.style.backgroundColor = "white";
}
const currencySymbol = await this.orm.call('res.currency', 'read',[record.data.currency_id[0]])
const mainKanbanDiv = this.__owl__.bdom.parentEl.ownerDocument.querySelector('#base_accounting_reconcile')
const existingRow = this.__owl__.bdom.parentEl.ownerDocument.querySelector(`tr[data-resId="${record.resId}"]`)
const stateLineRow = this.__owl__.bdom.parentEl.ownerDocument.querySelector('.statement_row')
if (stateLineRow){
const dataIdValue = stateLineRow.getAttribute('data-id');
if(dataIdValue == record.resId){
mainKanbanDiv.removeChild(stateLineRow);
}
}
if (existingRow) {
mainKanbanDiv.removeChild(existingRow);
} else {
// If the row doesn't exist, create and add it
const dateObject = new Date(record.data.date);
const year = dateObject.getFullYear();
const month = String(dateObject.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed
const day = String(dateObject.getDate()).padStart(2, '0');
const formattedDate = `${year}-${month}-${day}`;
let amount = parseFloat(record.data.amount_residual);
let debitColumn = '';
let creditColumn = '';
let partnerName = '';
let moveId = '';
// Check if partner_id exists and is not empty
if (record.data.partner_id && record.data.partner_id[1]) {
partnerName = record.data.partner_id[1];
}
if (record.data.move_id && record.data.move_id[1]) {
moveId = `<br/><span id="moveLine" style="font-size: 12px; font-style: italic;font-weight: normal;color: #01666b;cursor: pointer;" data-moveId="${record.data.move_id[0]}">${record.data.move_id[1]}</span>`;
}
if (amount < 0) {
debitColumn = `<td style="font-weight: bold; display: table-cell; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: top;">${currencySymbol[0].symbol} ${-amount}</td>`;
} else {
creditColumn = `<td style="font-weight: bold; display: table-cell; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: top;">${currencySymbol[0].symbol} ${amount}</td>`;
}
const newRow = document.createElement('tr');
newRow.setAttribute('data-resId', record.resId); // Set a unique identifier for the row
if (debitColumn !== '') {
newRow.innerHTML = `<td style="font-weight: bold; display: table-cell; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: top;">${record.data.account_id[1]}
${moveId}<span style="font-size: 12px;font-style: italic;font-weight: normal;"> : ${record.data.name}</span></td>
<td style="font-weight: bold; display: table-cell; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: top;">${partnerName}</td>
<td style="font-weight: bold; display: table-cell; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: top;">${formattedDate}</td>
${debitColumn}
<td style="font-weight: bold; display: table-cell; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: top;"> </td>
<td class="o_list_remove_record">
<button class="btn fa fa-trash-o" data-resId="${record.resId}"/>
</td>`;
} else if (creditColumn !== '') {
newRow.innerHTML = `<td style="font-weight: bold; display: table-cell; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: top;">${record.data.account_id[1]}
${moveId}<span style="font-size: 12px;font-style: italic;font-weight: normal;"> : ${record.data.name}</span></td>
<td style="font-weight: bold; display: table-cell; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: top;">${partnerName}</td>
<td style="font-weight: bold; display: table-cell; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: top;">${formattedDate}</td>
<td style="font-weight: bold; display: table-cell; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: top;"> </td>
${creditColumn}
<td class="o_list_remove_record">
<button class="btn fa fa-trash-o" data-resId="${record.resId}"/>
</td>`;
}
newRow.addEventListener('click', async () => {
const allRows = this.__owl__.bdom.parentEl.ownerDocument.querySelectorAll('tr[data-resId]');
allRows.forEach(row => {
row.classList.remove('selected-row');
});
newRow.classList.add('selected-row');
if (record.resId){
const manualOpsTab = this.__owl__.bdom.parentEl.ownerDocument.querySelector('[name="manual_operations_tab"]');
if (manualOpsTab) {
manualOpsTab.click();
const accountField = this.__owl__.bdom.parentEl.ownerDocument.querySelector('[name="account_id"]');
accountField.value = record.data.account_id[1];
}
}
});
// Append the new row to the mainKanbanDiv
mainKanbanDiv.appendChild(newRow);
const deleteButtons = this.__owl__.bdom.parentEl.ownerDocument.querySelectorAll('.fa-trash-o');
deleteButtons.forEach(button => {
button.addEventListener('click', async (event) => {
const resId = event.target.getAttribute('data-resId');
await this.removeRecord(resId);
});
});
const moveLine = this.__owl__.bdom.parentEl.ownerDocument.querySelectorAll('#moveLine');
moveLine.forEach(line => {
line.addEventListener('click',async (event) => {
const moveId = event.target.getAttribute('data-moveId');
await this.ShowMoveForm(moveId);
});
});
}
this.updateResIdList();
}
async removeRecord(resId){
const mainKanbanDiv = this.__owl__.bdom.parentEl.ownerDocument.querySelector('#base_accounting_reconcile');
const rowToRemove = this.__owl__.bdom.parentEl.ownerDocument.querySelector(`tr[data-resId="${resId}"]`);
if (rowToRemove) {
mainKanbanDiv.removeChild(rowToRemove);
this.updateResIdList();
}
}
async ShowMoveForm(moveId) {
// Convert moveId from string to integer
const moveIdInt = parseInt(moveId, 10);
// Check if the conversion is successful
if (!isNaN(moveIdInt)) {
this.action.doAction({
type: 'ir.actions.act_window',
res_model: 'account.move',
res_id: moveIdInt,
views: [[false, "form"]],
target: 'current',
});
}
}
updateResIdList() {
// Get all resId values from the current rows and update the resIdList array
const rows = this.__owl__.bdom.parentEl.ownerDocument.querySelectorAll('tr[data-resId]');
this.resIdList = Array.from(rows).map(row => parseInt(row.getAttribute('data-resId'), 10));
}
}
AccountMoveLineListController.template = 'base_accounting_kit.AccountMoveLineListController';
export const AccountMoveListView = {
...listView,
Controller: AccountMoveLineListController,
};
registry.category('views').add('account_move_line_list_controller', AccountMoveListView);

79
base_accounting_kit/static/src/js/bank_reconcile_form_lines_widget.js

@ -0,0 +1,79 @@
/** @odoo-module **/
import { registry } from '@web/core/registry';
import { useService } from "@web/core/utils/hooks";
import { _t } from "@web/core/l10n/translation";
const { Component, useState, useExternalListener } = owl;
export class BankReconcileFormLinesWidget extends Component {
setup(){
super.setup();
this.state = useState({statementLineResult: null,
MoveLineResult:null});
this.action = useService("action")
this.orm = useService("orm")
}
range(n){
return[...Array(Math.max(n,0)).keys()];
}
get record(){
return this.props.record;
}
async mountStatementLine(ev){
const manualOpsTab = document.querySelector('[name="manual_operations_tab"]');
if (manualOpsTab) {
manualOpsTab.click();
}
}
async onclickLink(ev){
const id = ev.currentTarget.dataset.id;
if (id) {
this.action.doAction({
type: 'ir.actions.act_window',
res_model: 'account.move',
res_id: parseInt(id),
views: [[false, "form"]],
target: 'current',
});
}
}
async removeRecord(ev){
ev.preventDefault();
var button = ev.currentTarget;
var row = button.closest('tr');
var firstRow = document.querySelector('.o_data_row:first-child');
var data_id = firstRow.dataset.id;
try {
await this.orm.call('account.bank.statement.line', 'write', [[parseInt(data_id)], {'lines_widget_json': null}]);
// Update the UI or perform any other actions as needed
} catch (error) {
console.error('Error removing lines_widget_json:', error);
// Handle the error as needed
}
row.remove();
}
getRenderValues(){
var self=this;
let data = this.props.record.context
this.orm.call('account.bank.statement.line', 'update_rowdata', [this.props.record.data.id])
let columns=[
["account",_t("Account")],
["partner",_t("Partner")],
["date",_t("Date")],
];
if(data.display_analytic_account_column){
columns.push(["analytic_account", _t("Analytic Account")]);
}
if(data.display_multi_currency_column){
columns.push(["amount_currency", _t("Amount in Currency")], ["currency", _t("Currency")]);
}
if(data.display_taxes_column){
columns.push(["taxes", _t("Taxes")]);
}
columns.push(["debit", _t("Debit")], ["credit", _t("Credit")], ["__trash", ""]);
return {...data,columns:columns}
}
}
BankReconcileFormLinesWidget.template = 'base_accounting_kit.bank_reconcile_widget_lines_widget';
export const FormLines = {
component: BankReconcileFormLinesWidget
}
registry.category("fields").add('bank_reconcile_widget_lines_widget', FormLines)

124
base_accounting_kit/static/src/js/bank_reconcile_form_list_widget.js

@ -0,0 +1,124 @@
/** @odoo-module **/
import { registry } from '@web/core/registry';
import { standardWidgetProps } from "@web/views/widgets/standard_widget_props";
import { View } from "@web/views/view";
const { Component, useSubEnv } = owl;
class FormListView extends Component {
setup(){
useSubEnv({
config:{},
});
}
get bankReconcileListViewProps(){
return{
type:'list',
display:{
controlPanel:{
"top-left":false,
"bottom-left":false,
}
},
resModel:this.props.resModel,
searchMenuTypes:["filter"],
allowSelectors:false,
searchViewId:false,
searchViewArch: `
<search>
<field name="name" string="Journal Item"/>
<field name="journal_id"/>
<field name="account_id"/>
<field name="partner_id"/>
<field name="move_id"/>
<field name="currency_id" groups="base.group_multi_currency"/>
<field name="date" string="Date"/>
<separator/>
<filter name="amount_received" string="Incoming" domain="[('balance','>',0.0)]"/>
<filter name="amount_paid" string="Outgoing" domain="[('balance','&lt;',0.0)]"/>
<separator name="inject_after"/>
<filter name="date" string="Date" date="date"/>
<filter string="Customer/Vendor" name="partner_id" domain="[]"/>
<filter string="Miscellaneous" domain="[('journal_id.type', '=', 'general')]" name="misc_filter"/>
</search>
`,
searchViewFields: {
name: {
name:"name",
string:"Journal Item",
type:"char",
store: true,
sortable: true,
searchable: true,
},
date: {
name: "date",
string: "Date",
type: "date",
store: true,
sortable: true,
searchable: true,
},
journal_id: {
name: "journal_id",
string: "Journal",
type: "many2one",
store: true,
sortable: true,
searchable: true,
},
account_id: {
name: "account_id",
string: "Account",
type: "many2one",
store: true,
sortable: true,
searchable: true,
},
partner_id: {
name: "partner_id",
string: "Partner",
type: "many2one",
store: true,
sortable: true,
searchable: true,
group_by:"partner_id",
},
currency_id: {
name: "currency_id",
string: "Currency",
type: "many2one",
store: true,
sortable: true,
searchable: true,
},
move_id: {
name:"move_id",
string:"Journal Entry",
type:"many2one",
store:true,
sortable:true,
searchable:true,
filter_domain:"['|',('move_id.name','ilike',self),('move_id.ref','ilike',self)]",
},
},
context:{
list_view_ref:"base_accounting_kit.account_move_line_view_tree",
}
}
}
}
FormListView.template = "base_accounting_kit.FormListView";
FormListView.components = { View };
FormListView.props = {
...standardWidgetProps,
resModel: { type: String },
};
export const formListView = {
component: FormListView,
extractProps: ({ attrs }) => ({
resModel: attrs.resModel,
}),
};
registry.category("view_widgets").add("form_list_view", formListView);

1
base_accounting_kit/static/src/scss/style.scss

@ -214,7 +214,6 @@
} }
.accounts-dashboard-wrap .info-box .info-box-icon { .accounts-dashboard-wrap .info-box .info-box-icon {
border-radius: .25rem; border-radius: .25rem;
-ms-flex-align: center; -ms-flex-align: center;
align-items: center; align-items: center;

33
base_accounting_kit/static/src/xml/bank_rec_widget.xml

@ -0,0 +1,33 @@
<templates>
<t t-name="base_accounting_kit.CustomKanbanView" t-inherit="web.KanbanView"
owl="1">
<xpath expr="//Layout" position="inside">
<div class="h-100 form_view_class">
<View t-if="state.selectedStLineId"
t-props="prepareFormPropsBankReconcile"
t-key="state.selectedStLineId"/>
</div>
</xpath>
</t>
<t t-name="base_accounting_kit.BankRecKanbanRenderer"
t-inherit="web.KanbanRenderer" t-inherit-mode="primary" owl="1">
<xpath expr="//div[hasclass('o_kanban_renderer')]"
position="before">
</xpath>
<xpath expr="//div[hasclass('o_kanban_renderer')]"
position="attributes">
<attribute name="class">o_kanban_renderer o_custom_class</attribute>
</xpath>
<xpath expr="//div[hasclass('o_custom_class')]"
position="attributes">
<attribute name="style">width:30%;</attribute>
</xpath>
</t>
<t t-name="base_accounting_kit.BankReconcileKanbanRecord"
t-inherit="web.KanbanRecord" t-inherit-mode="primary" owl="1">
</t>
<t t-name="base_accounting_kit.AccountMoveLineListController"
t-inherit="web.ListView"
t-inherit-mode="primary" owl="1">
</t>
</templates>

124
base_accounting_kit/static/src/xml/bank_reconcile_widget.xml

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8" ?>
<templates id="template" xml:space="preserve">
<t t-name="base_accounting_kit.bank_reconcile_widget_lines_widget">
<t t-set="data" t-value="getRenderValues()"/>
<div class="o_list_renderer table-responsive">
<table class="table table-sm position-relative mb-0 o_list_table_ungrouped table-striped o_bank_reconcile_lines_widget_line">
<thead>
<tr>
<t t-foreach="data.columns" t-as="column"
t-key="column[0]">
<th t-esc="column[1]"/>
</t>
</tr>
</thead>
<tbody id="base_accounting_reconcile">
<t t-if="data.default_lines_widget">
<t t-foreach="data.default_lines_widget" t-as="line"
t-key="line.id">
<tr class="o_data_row"
t-on-click="mountStatementLine"
t-att-data-id="line.id">
<t t-set="account"
t-value="line.account_code+' '+line.account_name"/>
<t t-set="amount"
t-value="line.currency_symbol+' '+line.amount"/>
<td class="o_data_cell o_field_cell"
style="font-weight: bolder;"
field="account_id">
<t t-esc="account"/>
<br/>
<span class="text-muted"
style="font-style: italic;">
<t t-esc="line.payment_ref"/>
</span>
</td>
<t t-if="line.partner_id">
<td field="partner_id"
t-esc="line.partner_id[1]"
style="font-weight: bolder;"/>
</t>
<t t-else="">
<td t-esc="line.partner_id[1]"/>
</t>
<td field="date"
t-esc="line.date"
style="font-weight: bolder;"/>
<t t-if="line.amount &gt; 0">
<td field="debit"
t-esc="amount"
style="font-weight: bolder;"/>
</t>
<t t-else="">
<td t-esc="' '"/>
</t>
<t t-if="line.amount &lt; 0">
<td field="credit"
t-esc="amount"
style="font-weight: bolder;"/>
</t>
</tr>
</t>
</t>
<t t-if="data.default_move_line">
<tr class="o_data_row statement_row"
t-on-click="mountStatementLine"
t-att-data-id="data.default_move_line.id">
<t t-set="amount_residual"
t-value="data.default_move_line.currency_symbol+' '+data.default_move_line.amount_residual"/>
<t t-set="move_account"
t-value="data.default_move_line.account_code+' '+data.default_move_line.account_name"/>
<td class="o_data_cell o_field_cell"
style="font-weight: bolder;">
<t t-esc="move_account"/>
<br/>
<span style="font-size: 12px; font-style: italic;font-weight: normal;color: #01666b;cursor: pointer;"
t-att-data-id="data.default_move_line.numeric_move_id"
t-on-click="onclickLink">
<t t-esc="data.default_move_line.move_name"/>
</span>
:
<span class="text-muted"
style="font-style: italic;">
<t t-esc="data.default_move_line.name"/>
</span>
</td>
<t t-if="data.default_move_line.partner_id">
<td t-esc="data.default_move_line.partner_name"
style="font-weight: bolder;"/>
</t>
<t t-else="">
<td t-esc="data.default_move_line.partner_name"/>
</t>
<td t-esc="data.default_move_line.date"
style="font-weight: bolder;"/>
<t t-if="data.default_move_line.amount_residual &lt; 0">
<td t-esc="amount_residual"
style="font-weight: bolder;"/>
</t>
<t t-else="">
<td t-esc="' '"/>
</t>
<t t-if="data.default_move_line.amount_residual &gt; 0">
<td t-esc="amount_residual"
style="font-weight: bolder;"/>
</t>
<t t-if="this.props.record.data.bank_state!='reconciled'">
<td class="o_list_remove_record">
<button class="btn fa fa-trash-o"
style="margin-top: -4px;"
t-on-click="removeRecord"/>
</td>
</t>
</tr>
</t>
</tbody>
</table>
</div>
</t>
<t t-name="base_accounting_kit.FormListView" owl="1">
<t t-if="props.record.id">
<View t-props="bankReconcileListViewProps"/>
</t>
</t>
</templates>

1
base_accounting_kit/wizard/__init__.py

@ -25,6 +25,7 @@ from . import account_balance_report
from . import account_bank_book_report from . import account_bank_book_report
from . import account_cash_book_report from . import account_cash_book_report
from . import account_day_book_report from . import account_day_book_report
from . import account_lock_date
from . import account_print_journal from . import account_print_journal
from . import account_report_general_ledger from . import account_report_general_ledger
from . import account_report_partner_ledger from . import account_report_partner_ledger

64
base_accounting_kit/wizard/account_lock_date.py

@ -0,0 +1,64 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import api, fields, models, SUPERUSER_ID, _
from odoo.exceptions import UserError
class AccountUpdateLockDate(models.TransientModel):
_name = 'account.lock.date'
_description = 'Lock date for accounting'
company_id = fields.Many2one(comodel_name='res.company', string="Company",
required=True)
sale_lock_date = fields.Date(string="Sales Lock Date", help='Prevents creating and modifying invoices up to the date.')
purchase_lock_date = fields.Date(string="Purchase Lock date", help='Prevents creating and modifying bills up to the date.')
hard_lock_date = fields.Date(string="Lock Everyone",
help="No users, including Advisers, can edit accounts prior to and "
"inclusive of this date. Use it for fiscal year locking for "
"example.")
@api.model
def default_get(self, field_list):
res = super(AccountUpdateLockDate, self).default_get(field_list)
company = self.env.company
res.update({
'company_id': company.id,
'sale_lock_date': company.sale_lock_date,
'purchase_lock_date': company.purchase_lock_date,
'hard_lock_date': company.hard_lock_date,
})
return res
def _check_execute_allowed(self):
self.ensure_one()
has_adviser_group = self.env.user.has_group(
'account.group_account_manager')
if not (has_adviser_group or self.env.uid == SUPERUSER_ID):
raise UserError(_("You are not allowed to execute this action."))
def execute(self):
self.ensure_one()
self._check_execute_allowed()
self.company_id.sudo().write({
'sale_lock_date': self.sale_lock_date,
'purchase_lock_date': self.purchase_lock_date,
'hard_lock_date': self.hard_lock_date,
})

46
base_accounting_kit/wizard/account_lock_date_views.xml

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<!--Account Lock Date Form View-->
<record model="ir.ui.view" id="account_lock_date_view_form">
<field name="name">account.lock.date.view.form</field>
<field name="model">account.lock.date</field>
<field name="arch" type="xml">
<form>
<group>
<field name="company_id" invisible="1"/>
<label for="sale_lock_date"/>
<div class="d-flex">
<field name="sale_lock_date" class="oe_inline"/><span class="text-muted"><i>to lock invoices</i></span>
</div>
<label for="purchase_lock_date"/>
<div class="d-flex">
<field name="purchase_lock_date" class="oe_inline"/><span class="text-muted"><i>to lock bills</i></span>
</div>
<field name="hard_lock_date" class="oe_inline"/>
</group>
<footer>
<button string="Update" name="execute" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-default" special="cancel"/>
</footer>
</form>
</field>
</record>
<!--Action Account Lock Date-->
<record model="ir.actions.act_window" id="account_update_lock_date_act_window">
<field name="name">Lock your Fiscal Period</field>
<field name="res_model">account.lock.date</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<!--Menu Lock Dates-->
<menuitem id="actions_menu"
name="Actions"
sequence="500"
parent="account.menu_finance_entries"
groups="account.group_account_manager"/>
<menuitem id="menu_lock_dates"
name="Lock Dates"
action="account_update_lock_date_act_window"
parent="base_accounting_kit.actions_menu"
groups="account.group_account_manager"/>
</odoo>
Loading…
Cancel
Save