|
After Width: | Height: | Size: 140 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 69 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 222 KiB |
Before Width: | Height: | Size: 767 KiB |
After Width: | Height: | Size: 90 KiB |
@ -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); |
@ -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); |
@ -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) |
@ -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','<',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); |
@ -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> |
@ -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 > 0"> |
|||
<td field="debit" |
|||
t-esc="amount" |
|||
style="font-weight: bolder;"/> |
|||
</t> |
|||
<t t-else=""> |
|||
<td t-esc="' '"/> |
|||
</t> |
|||
<t t-if="line.amount < 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 < 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 > 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> |
@ -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, |
|||
}) |
@ -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> |