Merge pull request #3826 from expsa/dev_odex25_accounting

Dev odex25 accounting
This commit is contained in:
kchyounes19 2025-07-08 15:51:41 +01:00 committed by GitHub
commit d09f5a27f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 287 additions and 70 deletions

View File

@ -20,7 +20,7 @@ This course provides a comprehensive, hands-on guide to managing employee custod
'version': '0.1',
# any module necessary for this one to work correctly
'depends': ['base','hr','account','exp_payroll_custom','hr_expense','odex25_account_reports','system_dashboard_classic','odex_takaful','exp_budget_check'],
'depends': ['base','hr','account','exp_payroll_custom','hr_expense','odex25_account_reports','system_dashboard_classic','exp_budget_check'],
# always loaded
'data': [

View File

@ -17,17 +17,10 @@ class AccountJournalInherit(models.Model):
help='Partner associated with this journal'
)
@api.constrains('custody_journal', 'partner_id')
def _check_custody_partner(self):
for record in self:
if record.custody_journal and not record.partner_id:
raise ValidationError(
_('Partner is required when Custody Journal is enabled'))
@api.onchange('custody_journal')
def _onchange_custody_journal(self):
if not self.custody_journal:
self.partner_id = False
return {
'domain': {'default_account_id': []}
}

View File

@ -1,4 +1,4 @@
from odoo import models, _
from odoo import models, _ ,api
from odoo.exceptions import UserError
class AccountPayment(models.Model):
@ -97,3 +97,62 @@ class AccountPayment(models.Model):
move.write(move._cleanup_write_orm_values(move, move_vals_to_write))
pay.write(move._cleanup_write_orm_values(pay, payment_vals_to_write))
@api.depends('partner_id', 'destination_account_id', 'journal_id')
def _compute_is_internal_transfer(self):
for payment in self:
if self.journal_id.custody_journal:
continue
else:
is_partner_ok = payment.partner_id == payment.journal_id.company_id.partner_id
is_account_ok = payment.destination_account_id and payment.destination_account_id == payment.journal_id.company_id.transfer_account_id
payment.is_internal_transfer = is_partner_ok and is_account_ok
def action_post(self):
res = super().action_post()
for payment in self:
if not self.hr_request_pledge:
if payment.journal_id.custody_journal and payment.partner_id:
employee = self.env['hr.employee'].sudo().search([
('user_id.partner_id', '=', payment.partner_id.id)
], limit=1)
print("pledge")
if employee:
self.env['hr.request.pledge'].allocate_payment_to_pledges(
employee_id=employee.id,
journal_id=payment.journal_id.id,
amount=payment.amount
)
else:
print("its hr_request_pledge")
return res
# class AccountMove(models.Model):
# _inherit = 'account.move'
#
# def action_post(self):
# res = super(AccountMove, self).action_post()
#
# for move in self:
# if move.payment_id and move.payment_id.is_custody_journal and move.payment_id.custody_partner_id:
#
# custody_partner = move.payment_id.custody_partner_id
#
#
# employee = self.env['hr.employee'].search([
# ('user_id.partner_id', '=', custody_partner.id)
# ], limit=1)
#
# if employee:
# self.env['hr.request.pledge'].allocate_payment_to_pledges(
# employee_id=employee.id,
# journal_id=move.journal_id.id,
# amount=move.amount
# )
#
# return res

View File

@ -103,7 +103,6 @@ class HrRequestPledge(models.Model):
@api.model
def allocate_payment_to_pledges(self, employee_id, journal_id, amount):
"""
@ -250,7 +249,8 @@ class HrRequestPledge(models.Model):
}
payment = self.env['account.payment'].create(payment_vals)
payment.flush()
payment.refresh()
employee_partner = self.employee_id.user_id.partner_id
if employee_partner:
@ -340,14 +340,14 @@ class HrExpenseSheetPledge(models.Model):
def _onchange_bank_journal_id(self):
self.account_payment_method_id = False
def action_sheet_move_create(self):
for sheet in self:
if sheet.payment_mode == 'company_account' and not (sheet.bank_journal_id and sheet.account_payment_method_id):
raise UserError(
_("Please enter Bank Journal and Payment Method!")
)
return super(HrExpenseSheetPledge, self).action_sheet_move_create()
# def action_sheet_move_create(self):
# for sheet in self:
# if sheet.payment_mode == 'company_account' and not (sheet.bank_journal_id and sheet.account_payment_method_id):
# raise UserError(
# _("Please enter Bank Journal and Payment Method!")
# )
#
# return super(HrExpenseSheetPledge, self).action_sheet_move_create()
# class AchievingBudgetAchievingBudget(models.Model):

View File

@ -10,9 +10,6 @@
<xpath expr="//field[@name='type']" position="after">
<field name="custody_journal"/>
<field name="partner_id"
attrs="{'invisible': [('custody_journal', '=', False)],
'required': [('custody_journal', '=', True)]}"/>
</xpath>
</field>

View File

@ -13,17 +13,17 @@
</xpath>
</field>
</record> -->
<record id="view_hr_expense_sheet_form_inherit_pledge" model="ir.ui.view">
<field name="name">view.hr.expense.sheet.form.inherit.pledge</field>
<field name="model">hr.expense.sheet</field>
<field name="inherit_id" ref="hr_expense.view_hr_expense_sheet_form"/>
<field name="arch" type="xml">
<xpath expr="//page[@name='other_info']/group/group/field[@name='bank_journal_id']" position="after">
<field name="available_account_payment_method_ids" invisible="1"/>
<field name="account_payment_method_id" domain="[('id', 'in', available_account_payment_method_ids)]"/>
</xpath>
</field>
</record>
<!-- <record id="view_hr_expense_sheet_form_inherit_pledge" model="ir.ui.view">-->
<!-- <field name="name">view.hr.expense.sheet.form.inherit.pledge</field>-->
<!-- <field name="model">hr.expense.sheet</field>-->
<!-- <field name="inherit_id" ref="hr_expense.view_hr_expense_sheet_form"/>-->
<!-- <field name="arch" type="xml">-->
<!-- <xpath expr="//page[@name='other_info']/group/group/field[@name='bank_journal_id']" position="after">-->
<!-- <field name="available_account_payment_method_ids" invisible="1"/>-->
<!-- <field name="account_payment_method_id" domain="[('id', 'in', available_account_payment_method_ids)]"/>-->
<!-- </xpath>-->
<!-- </field>-->
<!-- </record>-->
<record id="view_employee_journal_form_inherit" model="ir.ui.view">
<field name="name">hr.employee.journal.form.inherit</field>
@ -129,7 +129,7 @@
<field name="department_id"/>
<field name="job_id"/>
<field name="description"/>
<field name="spent_amount"/>
<field name="spent_amount" readonly="1"/>
<field name="custody_status" invisible="1"/>
<field name="remaining_amount"/>

View File

@ -136,30 +136,25 @@ class AccountPaymentRegister(models.TransientModel):
for line in payment.move_id.line_ids:
if line.debit > 0:
if line.credit > 0:
line.write({'partner_id': self.custody_partner_id.id})
employee = self.env['hr.employee'].search([
('user_id.partner_id', '=', self.custody_partner_id.id)
], limit=1)
if employee:
self.env['hr.request.pledge'].allocate_payment_to_pledges(
employee_id=employee.id,
journal_id=self.journal_id.id,
amount=payment.amount
)
return payments
def action_create_payments(self):
# Call the original method to create payments
for payment in self:
if payment.is_custody_journal and not payment.custody_partner_id:
raise UserError(
_("دفتر العهدة يتطلب تعيين شريك (custody_partner_id). الرجاء التحقق من إعدادات الدفتر."))
payments = self._create_payments()
# Update `move_id` values to include `takaful_sponsorship_id`
if self.is_refund_sponsorship:
for payment in payments:
if payment.move_id: # Ensure the payment has a move_id
payment.move_id.takaful_sponsorship_id = self.takaful_sponsorship_id.id
# if self.is_refund_sponsorship:
# for payment in payments:
# if payment.move_id: # Ensure the payment has a move_id
# payment.move_id.takaful_sponsorship_id = self.takaful_sponsorship_id.id
# Prepare the action for redirection
action = {

View File

@ -33,6 +33,8 @@ Add asset operations (Transfer, Sell/Dispose, Maitenenace, Assesment)
'data/asset_data.xml',
'data/asset_cron.xml',
'reports/reports.xml',
'reports/asset_barcode_pdf_report.xml',
'reports/asset_barcode_zpl_report.xml',
'views/account_asset_view.xml',
'views/account_asset_adjustment_view.xml',
'views/menus.xml',

View File

@ -890,3 +890,23 @@ msgstr "سجل تواصل الموقع"
#, python-format
msgid "You can not confirm operation without lines."
msgstr "لا يمكن تأكيد العملية دون إدخال التفاصيل"
#. module: exp_asset_base
#: model:ir.actions.report,name:exp_asset_base.label_barcode_account_asset
msgid "Asset Barcode (ZPL)"
msgstr "باركود الأصل (ZPL)"
#. module: exp_asset_base
#: model:ir.actions.report,print_report_name:exp_asset_base.report_account_asset_barcode
msgid "'Assets barcode - %s' % (object.name)"
msgstr "'باركود الأصول - %s' % (object.name)"
#. module: exp_asset_base
#: model:ir.actions.report,name:exp_asset_base.report_account_asset_barcode
msgid "Asset Barcode (PDF)"
msgstr "باركود الأصل (PDF)"
#. module: exp_asset_base
#: model_terms:ir.ui.view,arch_db:exp_asset_base.report_asset_barcode
msgid "<span class=\"text-muted\">No barcode available</span>"
msgstr "لا يوجد باركود متاح"

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="report_asset_barcode">
<div style="width: 32%; display: inline-table; height: 10rem;">
<table class="table table-bordered mb-0" style="border: 2px solid black;">
<tr>
<th class="table-active text-left" style="height: 4rem;">
<strong t-field="asset.display_name"/>
</th>
</tr>
<tr>
<td class="text-center align-middle" style="height: 6rem;">
<t t-if="asset.barcode">
<img alt="Barcode" t-if="len(asset.barcode) == 13" t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s' % ('EAN13', quote_plus(asset.barcode or ''), 600, 150)" style="width:100%;height:4rem;"/>
<img alt="Barcode" t-elif="len(asset.barcode) == 8" t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s' % ('EAN8', quote_plus(asset.barcode or ''), 600, 150)" style="width:100%;height:4rem;"/>
<img alt="Barcode" t-else="" t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s' % ('Code128', quote_plus(asset.barcode or ''), 600, 150)" style="width:100%;height:4rem"/>
<span t-field="asset.barcode"/>
</t>
<t t-else=""><span class="text-muted">No barcode available</span></t>
</td>
</tr>
</table>
</div>
</template>
<template id="report_assetbarcode">
<t t-call="web.basic_layout">
<div class="page">
<t t-foreach="docs" t-as="asset">
<t t-call="exp_asset_base.report_asset_barcode">
<t t-set="asset" t-value="asset"/>
</t>
</t>
</div>
</t>
</template>
<record id="report_account_asset_barcode" model="ir.actions.report">
<field name="name">Asset Barcode (PDF)</field>
<field name="model">account.asset</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">exp_asset_base.report_assetbarcode</field>
<field name="report_file">exp_asset_base.report_assetbarcode</field>
<field name="print_report_name">'Assets barcode - %s' % (object.name)</field>
<field name="binding_model_id" ref="exp_asset_base.model_account_asset"/>
<field name="binding_type">report</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="label_barcode_account_asset_view">
<t t-foreach="docs" t-as="asset">
<t t-translation="off">
^XA
^FO100,50
^A0N,44,33^FD<t t-esc="asset.display_name"/>^FS
<t t-if="asset.barcode">
^FO100,100^BY3
^BCN,100,Y,N,N
^FD<t t-esc="asset.barcode"/>^FS
</t>
^XZ
</t>
</t>
</template>
<record id="label_barcode_account_asset" model="ir.actions.report">
<field name="name">Asset Barcode (ZPL)</field>
<field name="model">account.asset</field>
<field name="report_type">qweb-text</field>
<field name="report_name">exp_asset_base.label_barcode_account_asset_view</field>
<field name="report_file">exp_asset_base.label_barcode_account_asset_view</field>
<field name="binding_model_id" ref="exp_asset_base.model_account_asset"/>
<field name="binding_type">report</field>
</record>
</data>
</odoo>

View File

@ -15,6 +15,8 @@ class AccountGeneralLedgerReport(models.AbstractModel):
filter_all_entries = False
filter_journals = True
filter_analytic = True
filter_partner = True
filter_unfold_all = False
@api.model

View File

@ -70,6 +70,7 @@ var M2MFilters = Widget.extend(StandaloneFieldManagerMixin, {
_.each(this.fields, function (filter, fieldName) {
data[fieldName] = self.widgets[fieldName].value.res_ids;
});
var changedFieldName = this._lastChangedFieldName || null;
this.trigger_up('value_changed', data);
return result;
},
@ -133,14 +134,29 @@ var accountReportsWidget = AbstractAction.extend({
custom_events: {
'value_changed': function(ev) {
var self = this;
var changedFields = [];
_.each(ev.data, function(value, key) {
var oldValue = self.report_options[key] || [];
var newValue = value || [];
if (!_.isEqual(oldValue.sort(), newValue.sort())) {
changedFields.push(key);
}
});
self.report_options.partner_ids = ev.data.partner_ids;
self.report_options.partner_categories = ev.data.partner_categories;
self.report_options.analytic_accounts = ev.data.analytic_accounts;
self.report_options.analytic_tags = ev.data.analytic_tags;
return self.reload().then(function () {
self.$searchview_buttons.find('.account_partner_filter').click();
self.$searchview_buttons.find('.account_analytic_filter').click();
});
return self.reload().then(function () {
if (changedFields.includes('partner_ids') || changedFields.includes('partner_categories')) {
self.$searchview_buttons.find('.account_partner_filter').click();
}
if (changedFields.includes('analytic_accounts') || changedFields.includes('analytic_tags')) {
self.$searchview_buttons.find('.account_analytic_filter').click();
}
});
},
},
@ -611,57 +627,111 @@ var accountReportsWidget = AbstractAction.extend({
// partner filter
if (this.report_options.partner) {
if (!this.M2MFilters) {
var fields = {};
if (!this.partnerM2MFilters) {
var partnerFields = {};
if ('partner_ids' in this.report_options) {
fields['partner_ids'] = {
partnerFields['partner_ids'] = {
label: _t('Partners'),
modelName: 'res.partner',
value: this.report_options.partner_ids.map(Number),
};
}
if ('partner_categories' in this.report_options) {
fields['partner_categories'] = {
partnerFields['partner_categories'] = {
label: _t('Tags'),
modelName: 'res.partner.category',
value: this.report_options.partner_categories.map(Number),
};
}
if (!_.isEmpty(fields)) {
this.M2MFilters = new M2MFilters(this, fields);
this.M2MFilters.appendTo(this.$searchview_buttons.find('.js_account_partner_m2m'));
if (!_.isEmpty(partnerFields)) {
this.partnerM2MFilters = new M2MFilters(this, partnerFields);
this.partnerM2MFilters.appendTo(this.$searchview_buttons.find('.js_account_partner_m2m'));
}
} else {
this.$searchview_buttons.find('.js_account_partner_m2m').append(this.M2MFilters.$el);
this.$searchview_buttons.find('.js_account_partner_m2m').append(this.partnerM2MFilters.$el);
}
}
// analytic filter
if (this.report_options.analytic) {
if (!this.M2MFilters) {
var fields = {};
if (!this.analyticM2MFilters) {
var analyticFields = {};
if (this.report_options.analytic_accounts) {
fields['analytic_accounts'] = {
analyticFields['analytic_accounts'] = {
label: _t('Accounts'),
modelName: 'account.analytic.account',
value: this.report_options.analytic_accounts.map(Number),
};
}
if (this.report_options.analytic_tags) {
fields['analytic_tags'] = {
analyticFields['analytic_tags'] = {
label: _t('Tags'),
modelName: 'account.analytic.tag',
value: this.report_options.analytic_tags.map(Number),
};
}
if (!_.isEmpty(fields)) {
this.M2MFilters = new M2MFilters(this, fields);
this.M2MFilters.appendTo(this.$searchview_buttons.find('.js_account_analytic_m2m'));
if (!_.isEmpty(analyticFields)) {
this.analyticM2MFilters = new M2MFilters(this, analyticFields);
this.analyticM2MFilters.appendTo(this.$searchview_buttons.find('.js_account_analytic_m2m'));
}
} else {
this.$searchview_buttons.find('.js_account_analytic_m2m').append(this.M2MFilters.$el);
this.$searchview_buttons.find('.js_account_analytic_m2m').append(this.analyticM2MFilters.$el);
}
}
// partner filter
// if (this.report_options.partner) {
// if (!this.M2MFilters) {
// var fields = {};
// if ('partner_ids' in this.report_options) {
// fields['partner_ids'] = {
// label: _t('Partners'),
// modelName: 'res.partner',
// value: this.report_options.partner_ids.map(Number),
// };
// }
// if ('partner_categories' in this.report_options) {
// fields['partner_categories'] = {
// label: _t('Tags'),
// modelName: 'res.partner.category',
// value: this.report_options.partner_categories.map(Number),
// };
// }
// if (!_.isEmpty(fields)) {
// this.M2MFilters = new M2MFilters(this, fields);
// this.M2MFilters.appendTo(this.$searchview_buttons.find('.js_account_partner_m2m'));
// }
// } else {
// this.$searchview_buttons.find('.js_account_partner_m2m').append(this.M2MFilters.$el);
// }
// }
//
// // analytic filter
// if (this.report_options.analytic) {
// if (!this.M2MFilters) {
// var fields = {};
// if (this.report_options.analytic_accounts) {
// fields['analytic_accounts'] = {
// label: _t('Accounts'),
// modelName: 'account.analytic.account',
// value: this.report_options.analytic_accounts.map(Number),
// };
// }
// if (this.report_options.analytic_tags) {
// fields['analytic_tags'] = {
// label: _t('Tags'),
// modelName: 'account.analytic.tag',
// value: this.report_options.analytic_tags.map(Number),
// };
// }
// if (!_.isEmpty(fields)) {
// this.M2MFilters = new M2MFilters(this, fields);
// this.M2MFilters.appendTo(this.$searchview_buttons.find('.js_account_analytic_m2m'));
// }
// } else {
// this.$searchview_buttons.find('.js_account_analytic_m2m').append(this.M2MFilters.$el);
// }
// }
//
},
format_date: function(moment_date) {
var date_format = 'YYYY-MM-DD';