Merge branch 'dev_odex25_ensan' of https://github.com/expsa/odex25-standard-modules into notes_7

This commit is contained in:
Nossibaelhadi 2025-11-10 01:08:53 +03:00
commit bee9e9390d
16 changed files with 281 additions and 237 deletions

View File

@ -2,13 +2,13 @@
<odoo> <odoo>
<data> <data>
<!-- Used to bring a menu inside action menu --> <!-- Used to bring a menu inside action menu -->
<record id="server_action_exchange_orders" model="ir.actions.server"> <record id="server_action_accounting_transfer" model="ir.actions.server">
<field name="name">Exchange orders</field> <field name="name">Accounting Transfer</field>
<field name="model_id" ref="odex_benefit.model_service_request"/> <field name="model_id" ref="odex_benefit.model_service_request"/>
<field name="binding_model_id" ref="odex_benefit.model_service_request"/> <field name="binding_model_id" ref="odex_benefit.model_service_request"/>
<field name="state">code</field> <field name="state">code</field>
<field name="code"> <field name="code">
action = records.action_create_payment_order() action = records.action_accounting_transfer()
</field> </field>
</record> </record>
@ -22,15 +22,6 @@
</field> </field>
</record> </record>
<record id="server_action_vendor_bill" model="ir.actions.server">
<field name="name">Create Vendor Bill</field>
<field name="model_id" ref="odex_benefit.model_service_request"/>
<field name="binding_model_id" ref="odex_benefit.model_service_request"/>
<field name="state">code</field>
<field name="code">action = records.create_vendor_bill()</field>
</record>
<record id="action_assign_visit_sequence" model="ir.actions.server"> <record id="action_assign_visit_sequence" model="ir.actions.server">
<field name="name">Assign Visit Sequence</field> <field name="name">Assign Visit Sequence</field>
<field name="model_id" ref="odex_benefit.model_visit_location"/> <field name="model_id" ref="odex_benefit.model_visit_location"/>

View File

@ -4523,8 +4523,6 @@ msgstr ""
#: model:ir.model.fields.selection,name:odex_benefit.selection__receive_benefit_zkat__state__done #: model:ir.model.fields.selection,name:odex_benefit.selection__receive_benefit_zkat__state__done
#: model:ir.model.fields.selection,name:odex_benefit.selection__receive_food_basket__state__done #: model:ir.model.fields.selection,name:odex_benefit.selection__receive_food_basket__state__done
#: model:ir.model.fields.selection,name:odex_benefit.selection__visit_location__state__done #: model:ir.model.fields.selection,name:odex_benefit.selection__visit_location__state__done
#: model:ir.model.fields.selection,name:odex_benefit.selection__payment_orders__state__done
#: model:ir.model.fields.selection,name:odex_benefit.selection__seasonal_service__state__done
#: model_terms:ir.ui.view,arch_db:odex_benefit.appliances_furniture_form #: model_terms:ir.ui.view,arch_db:odex_benefit.appliances_furniture_form
#: model_terms:ir.ui.view,arch_db:odex_benefit.benefit_club_form #: model_terms:ir.ui.view,arch_db:odex_benefit.benefit_club_form
#: model_terms:ir.ui.view,arch_db:odex_benefit.benefit_food_basket_form #: model_terms:ir.ui.view,arch_db:odex_benefit.benefit_food_basket_form
@ -4537,6 +4535,12 @@ msgstr ""
msgid "Done" msgid "Done"
msgstr "تمت الزيارة" msgstr "تمت الزيارة"
#. module: odex_benefit
#: model:ir.model.fields.selection,name:odex_benefit.selection__payment_orders__state__done
#: model:ir.model.fields.selection,name:odex_benefit.selection__seasonal_service__state__done
msgid "Done"
msgstr "تم"
#. module: odex_benefit #. module: odex_benefit
#: model:ir.model.fields,field_description:odex_benefit.field_receive_appliances_furniture__donor_name #: model:ir.model.fields,field_description:odex_benefit.field_receive_appliances_furniture__donor_name
msgid "Donor Name" msgid "Donor Name"
@ -11513,7 +11517,7 @@ msgid "Total"
msgstr "الإجمالي" msgstr "الإجمالي"
#. module: odex_benefit #. module: odex_benefit
#: code:addons/odex_benefit/models/family_expense.py:0 #: code:addons/odex_benefit/models/payment_order.py:0
#, python-format #, python-format
msgid "Total Credit for Family Expenses" msgid "Total Credit for Family Expenses"
msgstr "ملفات تغذيه تحت الصرف" msgstr "ملفات تغذيه تحت الصرف"
@ -14307,6 +14311,7 @@ msgstr "إعتماد إدارة المالية"
#. module: odex_benefit #. module: odex_benefit
#: model:ir.model.fields.selection,name:odex_benefit.selection__service_request__state__accounting_approve #: model:ir.model.fields.selection,name:odex_benefit.selection__service_request__state__accounting_approve
#: model:ir.model.fields.selection,name:odex_benefit.selection__seasonal_service__state__accounting_approve
msgid "Accounting Approve" msgid "Accounting Approve"
msgstr "بانتظار المالية" msgstr "بانتظار المالية"
@ -14363,7 +14368,7 @@ msgstr "فئة الأسرة"
#: model:ir.model.fields,field_description:odex_benefit.field_seasonal_grant_benefit__aid_amount #: model:ir.model.fields,field_description:odex_benefit.field_seasonal_grant_benefit__aid_amount
#: model:ir.model.fields,field_description:odex_benefit.field_seasonal_service__aid_amount #: model:ir.model.fields,field_description:odex_benefit.field_seasonal_service__aid_amount
msgid "Aid Amount" msgid "Aid Amount"
msgstr "مبلغ المساعدة" msgstr "قيمة الخدمة"
#. module: odex_benefit #. module: odex_benefit
#: model:ir.model.fields,field_description:odex_benefit.field_seasonal_service__family_count #: model:ir.model.fields,field_description:odex_benefit.field_seasonal_service__family_count
@ -14378,7 +14383,7 @@ msgstr "عدد الأفراد المستفيدين"
#. module: odex_benefit #. module: odex_benefit
#: model:ir.model.fields,field_description:odex_benefit.field_seasonal_service__family_disbursement_total_amount #: model:ir.model.fields,field_description:odex_benefit.field_seasonal_service__family_disbursement_total_amount
msgid "Total Family Disbursement Amount" msgid "Total Family Disbursement Amount"
msgstr "إجمالي مبلغ صرف الخدمة للأسر" msgstr "الأجمالي"
#. module: odex_benefit #. module: odex_benefit
#: model:ir.model.fields,field_description:odex_benefit.field_seasonal_grant_benefit__family_id #: model:ir.model.fields,field_description:odex_benefit.field_seasonal_grant_benefit__family_id
@ -14411,7 +14416,6 @@ msgid "Expenses Account"
msgstr "حساب المصروف" msgstr "حساب المصروف"
#. module: odex_benefit #. module: odex_benefit
#: model:ir.actions.server,name:odex_benefit.server_action_exchange_orders
#: model:ir.actions.server,name:odex_benefit.server_action_seasonal_service_exchange_orders #: model:ir.actions.server,name:odex_benefit.server_action_seasonal_service_exchange_orders
msgid "Exchange orders" msgid "Exchange orders"
msgstr "أمر الصرف" msgstr "أمر الصرف"
@ -14438,6 +14442,11 @@ msgstr "أمر الصرف تم"
msgid "Payment Order Done" msgid "Payment Order Done"
msgstr "أمر الصرف تم" msgstr "أمر الصرف تم"
#. module: odex_benefit
#: model_terms:ir.ui.view,arch_db:odex_benefit.service_request_form
msgid "Payment Done"
msgstr "تم الدفع"
#. module: odex_benefit #. module: odex_benefit
#: model:ir.model.fields,field_description:odex_benefit.field_payment_orders__is_seasonal #: model:ir.model.fields,field_description:odex_benefit.field_payment_orders__is_seasonal
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__is_seasonal #: model:ir.model.fields,field_description:odex_benefit.field_service_request__is_seasonal
@ -16913,7 +16922,6 @@ msgstr "يجب إضافة طلب خدمة واحد على الأقل."
#. module: odex_benefit #. module: odex_benefit
#: code:addons/odex_benefit/models/service_request.py:0 #: code:addons/odex_benefit/models/service_request.py:0
#: code:addons/odex_benefit/models/service_request.py:0
#, python-format #, python-format
msgid "" msgid ""
"All selected service requests must belong to the same Service Cat.\n" "All selected service requests must belong to the same Service Cat.\n"
@ -16924,7 +16932,6 @@ msgstr "يجب أن تنتمي جميع طلبات الخدمة المحددة
#. module: odex_benefit #. module: odex_benefit
#: code:addons/odex_benefit/models/service_request.py:0 #: code:addons/odex_benefit/models/service_request.py:0
#: code:addons/odex_benefit/models/service_request.py:0
#, python-format #, python-format
msgid "" msgid ""
"The following service requests do not meet the conditions:\n" "The following service requests do not meet the conditions:\n"
@ -16933,20 +16940,17 @@ msgid ""
"• Be in 'Accounting Approve' state\n" "• Be in 'Accounting Approve' state\n"
"• Have payment order state = 'None'\n" "• Have payment order state = 'None'\n"
"• Not be linked to any payment order" "• Not be linked to any payment order"
msgstr "طلبات الخدمة التالية لا تستوفي الشروط:\n%s\nيجب أن يكون كل طلب:\n• في حالة 'موافقة المحاسبة'\n• حالة أمر الدفع = 'لا يوجد'\n• غير مرتبط بأي أمر دفع" msgstr "طلبات الخدمة التالية لا تستوفي الشروط:\n%s\nيجب أن يكون كل طلب:\n• في حالة 'بانتظار المالية'\n• حالة أمر الدفع = 'لا يوجد'\n• غير مرتبط بأي أمر دفع"
#. module: odex_benefit
#: code:addons/odex_benefit/models/service_request.py:0
#, python-format
msgid "Only 'Electrical Devices' service cat requests can create a invoice."
msgstr "يمكن فقط لطلبات فئة خدمة 'الأجهزة الكهربائية' إنشاء فاتورة."
#. module: odex_benefit #. module: odex_benefit
#: model_terms:ir.ui.view,arch_db:odex_benefit.payment_orders_form #: model_terms:ir.ui.view,arch_db:odex_benefit.payment_orders_form
msgid "Manager approval" msgid "Manager approval"
msgstr "موافقة المسؤول" msgstr "موافقة المسؤول"
#. module: odex_benefit
#: model_terms:ir.ui.view,arch_db:odex_benefit.service_request_form
msgid "Payment Waiting"
msgstr "في انتظار الدفع"
#. module: odex_benefit #. module: odex_benefit
#: code:addons/odex_benefit/models/service_request.py:0 #: code:addons/odex_benefit/models/service_request.py:0

View File

@ -82,7 +82,8 @@ class ConfirmBenefitExpense(models.Model):
family_domain_ids = fields.Many2many(comodel_name='grant.benefit', compute='_compute_domain_ids') family_domain_ids = fields.Many2many(comodel_name='grant.benefit', compute='_compute_domain_ids')
journal_domain_ids = fields.Many2many(comodel_name='account.journal', compute='_compute_domain_ids') journal_domain_ids = fields.Many2many(comodel_name='account.journal', compute='_compute_domain_ids')
company_id = fields.Many2one('res.company', default=lambda self: self.env.company) company_id = fields.Many2one('res.company', default=lambda self: self.env.company)
currency_id = fields.Many2one(comodel_name='res.currency',string="Company Currency",related='company_id.currency_id') currency_id = fields.Many2one(comodel_name='res.currency', string="Company Currency",
related='company_id.currency_id')
@api.model @api.model
def create(self, vals): def create(self, vals):
@ -111,7 +112,7 @@ class ConfirmBenefitExpense(models.Model):
self.ensure_one() self.ensure_one()
for line in self.benefit_expense_line_ids: for line in self.benefit_expense_line_ids:
family = line.family_id family = line.family_id
income,meals,clotting = 0,0,0 income, meals, clotting = 0, 0, 0
if not family: if not family:
continue continue
monthly_meals = family.family_monthly_meals monthly_meals = family.family_monthly_meals
@ -439,16 +440,12 @@ class ConfirmBenefitExpense(models.Model):
if not credit_account_id: if not credit_account_id:
raise UserError(_("Please select credit account.")) raise UserError(_("Please select credit account."))
inv_lines = [] self.env['payment.orders'].create({
total_credit = 0 'state': 'draft',
credit_line_name = _("Total Credit for Family Expenses") 'accountant_id': validation_setting.accountant_id.id,
for line in lines: 'benefit_expense_line_ids': [(6, 0, rec.benefit_expense_line_ids.ids)],
sum_line, credit_total = rec._prepare_entry_lines(line,validation_setting) 'type': 'benefit_expense',
total_credit += credit_total })
inv_lines += sum_line
inv_lines.append(self._create_credit_line(credit_account_id, total_credit, credit_line_name))
rec.create_entry(rec.journal_id.id, inv_lines)
else: else:
account_id = validation_setting.meal_expense_account_id account_id = validation_setting.meal_expense_account_id
invoice_lines = [] invoice_lines = []
@ -478,61 +475,3 @@ class ConfirmBenefitExpense(models.Model):
rec.state = 'confirm' rec.state = 'confirm'
return True return True
def _prepare_entry_lines(self, line,validation_setting):
"""Prepare debit and credit lines for a benefit"""
entry_lines = []
total_credit_amount = 0
expense_types = [
('family_monthly_income', 'cash_expense', validation_setting.cash_expense_account_id.id),
('family_monthly_meals', 'meal_expense',validation_setting.meal_expense_account_id.id ),
('family_monthly_clotting', 'clothing_expense', validation_setting.clothing_expense_account_id.id),
]
for field, expense_type, debit_account_id in expense_types:
amount = getattr(line, field, 0.0)
if amount:
name = _("Family Code - %s Family Expense - %s - %s/%s") % (
line.family_id.code, expense_type, self.name, self.family_expense_seq)
entry_lines.append(self._create_debit_line(line, debit_account_id, amount, name))
total_credit_amount += amount
return entry_lines, total_credit_amount
def _create_debit_line(self, line, account_id, amount, name):
"""Create a debit line"""
return (0, 0, {
'name': name,
'family_confirm_id': self.id,
'benefit_family_id': line.family_id.id,
'partner_id': line.family_id.partner_id.id,
'analytic_account_id': line.family_id.branch_custom_id.branch.analytic_account_id.id,
'account_id': account_id,
'debit': amount,
'credit': 0.0,
})
def _create_credit_line(self, account_id, amount, name):
"""Create a credit line"""
return (0, 0, {
'name': name,
'family_confirm_id': self.id,
'account_id': account_id,
'debit': 0.0,
'credit': amount,
})
def create_entry(self, journal_id, lines):
"""Create an account move entry"""
move_vals = {
'journal_id': journal_id,
'date': self.date,
# 'ref': self.name,
'ref': f'{self.name}/{self.family_expense_seq}',
'family_confirm_id': self.id,
'benefit_family_ids': [(6, 0, self.benefit_expense_line_ids.mapped('family_id').ids)],
'line_ids': lines,
}
move_id = self.env['account.move'].create(move_vals)
move_id.action_post()
return True

View File

@ -23,6 +23,7 @@ class BenefitExpenseLine(models.Model):
total_family_expenses = fields.Float(string="Total Family Expenses", compute='_compute_total_family_expenses') total_family_expenses = fields.Float(string="Total Family Expenses", compute='_compute_total_family_expenses')
start_date = fields.Date(string='Start Date', ) start_date = fields.Date(string='Start Date', )
end_date = fields.Date(string='End Date', ) end_date = fields.Date(string='End Date', )
payment_order_id = fields.Many2one('payment.orders', string='Payment Order', ondelete="set null", copy=False)
@api.depends('family_monthly_income', 'family_monthly_clotting', 'family_monthly_meals') @api.depends('family_monthly_income', 'family_monthly_clotting', 'family_monthly_meals')
def _compute_total_family_expenses(self): def _compute_total_family_expenses(self):

View File

@ -32,6 +32,7 @@ class FamilyValidationSetting(models.Model):
meal_partner_id = fields.Many2one('res.partner', string='Meal Partner') meal_partner_id = fields.Many2one('res.partner', string='Meal Partner')
journal_id = fields.Many2one('account.journal', string='Journal') journal_id = fields.Many2one('account.journal', string='Journal')
account_id = fields.Many2one('account.account',string='Expenses Account') account_id = fields.Many2one('account.account',string='Expenses Account')
accountant_id = fields.Many2one('res.users', string='Accountant')
@api.constrains('meal_expense_account_id', 'clothing_expense_account_id', 'cash_expense_account_id') @api.constrains('meal_expense_account_id', 'clothing_expense_account_id', 'cash_expense_account_id')
def _constraint_amount_should_be_positive_if_account_selected(self): def _constraint_amount_should_be_positive_if_account_selected(self):

View File

@ -22,6 +22,8 @@ class PaymentOrders(models.Model):
inverse='_inverse_service_type_id', inverse='_inverse_service_type_id',
store=True) store=True)
service_requests_ids = fields.One2many('service.request', 'payment_order_id', string='Service Requests') service_requests_ids = fields.One2many('service.request', 'payment_order_id', string='Service Requests')
benefit_expense_line_ids = fields.One2many('benefit.expense.line', 'payment_order_id',
string='Benefit Expense Lines')
seasonal_requests_ids = fields.One2many('seasonal.service', 'payment_order_id', string='Seasonal Requests') seasonal_requests_ids = fields.One2many('seasonal.service', 'payment_order_id', string='Seasonal Requests')
family_seasonal_requests_ids = fields.One2many('seasonal.grant.benefit', 'payment_order_id', family_seasonal_requests_ids = fields.One2many('seasonal.grant.benefit', 'payment_order_id',
string='Seasonal Requests') string='Seasonal Requests')
@ -31,11 +33,20 @@ class PaymentOrders(models.Model):
('waiting_head', 'Waiting for Head of Expenses Department'), ('waiting_head', 'Waiting for Head of Expenses Department'),
('waiting_finance', 'Waiting for Financial Manager'), ('waiting_finance', 'Waiting for Financial Manager'),
('waiting_gm', 'Waiting for General Manager'), ('waiting_gm', 'Waiting for General Manager'),
('waiting_deposit', 'Waiting for Deposit'),
('done', 'Done'), ('done', 'Done'),
('refused', 'Refused')], default='draft', tracking=True) ('refused', 'Refused')], default='draft', tracking=True)
is_seasonal = fields.Boolean(string='Is Seasonal Service?') is_seasonal = fields.Boolean(string='Is Seasonal Service?')
journal_id = fields.Many2one(comodel_name='account.journal', string="Journal", copy=False, journal_id = fields.Many2one(comodel_name='account.journal', string="Journal", copy=False,
domain="[('type','in',['cash','bank'])]", default=_default_journal) domain="[('type','in',['cash','bank'])]", required=True, default=_default_journal)
type = fields.Selection(
selection=[
('services', 'Services'),
('seasonal_services', 'Seasonal Services'),
('benefit_expense', 'Monthly Expense'),
],
string='Payment Order Type', required=True, default='services', )
move_id = fields.Many2one('account.move', ondelete='cascade')
def action_manager_approval(self): def action_manager_approval(self):
for rec in self: for rec in self:
@ -49,19 +60,42 @@ class PaymentOrders(models.Model):
def action_finance_approval(self): def action_finance_approval(self):
for rec in self: for rec in self:
account_move = self.env['account.move'].create(
{
'ref': f'{rec.payment_order_description}/{rec.ref_num}',
'journal_id': rec.journal_id.id,
'payment_order_id': rec.id,
'line_ids': rec.get_lines()
}
)
rec.state = 'waiting_gm' rec.state = 'waiting_gm'
def create_entry(self):
for rec in self:
vals = {}
line_ids = rec.get_lines()
move_vals = {
'journal_id': rec.journal_id.id,
# 'payment_order_id': rec.id, # bug
'line_ids': line_ids,
'ref': f'{rec.payment_order_description}/{rec.ref_num}',
}
if rec.type == "benefit_expense":
# ref1 = ", ".join(rec.benefit_expense_line_ids.mapped('name'))
# ref2 = ", ".join(rec.benefit_expense_line_ids.mapped('family_expense_seq'))
family_ids = rec.benefit_expense_line_ids.mapped('family_id').ids
move_vals.update({
# 'ref': ref1 + '/' + ref2,
'benefit_family_ids': [(6, 0, family_ids)],
})
move_id = self.env['account.move'].create(vals)
#move_id.action_post()
rec.move_id = move_id
def action_deposit(self):
for rec in self:
if rec.type == "seasonal_services":
rec.seasonal_requests_ids.action_accounting_approve()
elif rec.type == "services":
rec.service_requests_ids.write({'state':'action_accounting_approve'})
rec.state = 'done'
def action_gm_approval(self): def action_gm_approval(self):
for rec in self: for rec in self:
rec.state = 'done' rec.state = 'waiting_deposit'
def action_refuse(self): def action_refuse(self):
for rec in self: for rec in self:
@ -104,6 +138,12 @@ class PaymentOrders(models.Model):
res.name = self.env['ir.sequence'].sudo().next_by_code('payment.orders.sequence') or _('New') res.name = self.env['ir.sequence'].sudo().next_by_code('payment.orders.sequence') or _('New')
return res return res
def unlink(self):
for payment in self:
if payment.state not in ['draft']:
raise ValidationError(_('You cannot delete this record'))
return super(PaymentOrders, self).unlink()
@api.model @api.model
def search(self, args, offset=0, limit=None, order=None, count=False): def search(self, args, offset=0, limit=None, order=None, count=False):
if self.env.user and self.env.user.id and self.env.user.has_group( if self.env.user and self.env.user.id and self.env.user.has_group(
@ -129,26 +169,67 @@ class PaymentOrders(models.Model):
'domain': [('id', 'in', moves)], 'domain': [('id', 'in', moves)],
} }
def _prepare_entry_lines(self, line, validation_setting):
entry_lines = []
total_credit_amount = 0
expense_types = [
('family_monthly_income', 'cash_expense', validation_setting.cash_expense_account_id.id),
('family_monthly_meals', 'meal_expense', validation_setting.meal_expense_account_id.id),
('family_monthly_clotting', 'clothing_expense', validation_setting.clothing_expense_account_id.id),
]
for field, expense_type, debit_account_id in expense_types:
amount = getattr(line, field, 0.0)
if amount:
name = _("Family Code - %s Family Expense - %s - %s/%s") % (
line.family_id.code, expense_type, line.confirm_expense_id.name,
line.confirm_expense_id.family_expense_seq)
entry_lines.append(self._create_debit_line(line, debit_account_id, amount, name))
total_credit_amount += amount
return entry_lines, total_credit_amount
def _create_debit_line(self, line, account_id, amount, name):
"""Create a debit line"""
return (0, 0, {
'name': name,
'family_confirm_id': line.confirm_expense_id.id,
'benefit_family_id': line.family_id.id,
'partner_id': line.family_id.partner_id.id,
'analytic_account_id': line.family_id.branch_custom_id.branch.analytic_account_id.id,
'account_id': account_id,
'debit': amount,
'credit': 0.0,
})
def get_lines(self): def get_lines(self):
lines = [] lines = []
total_credit = 0 total_credit = 0
if self.service_requests_ids: # credit_line_name = _("Total Credit for Family Expenses")
for request in self.service_requests_ids: if self.type in ['seasonal_services', 'services']:
lines.append( if self.service_requests_ids:
{ for request in self.service_requests_ids:
'name': f'{"Family code"}{request.family_id.code}-{request.description}-{request.payment_order_id.name}-{request.payment_order_id.ref_num}', lines.append(
'benefit_family_id': request.family_id.id, {
'account_id': request.account_id.id, 'name': f'{"Family code"}{request.family_id.code}-{request.description}-{request.payment_order_id.name}-{request.payment_order_id.ref_num}',
'partner_id': request.family_id.partner_id.id, 'benefit_family_id': request.family_id.id,
'analytic_account_id': request.branch_custom_id.branch.analytic_account_id.id, 'account_id': request.account_id.id,
'debit': request.requested_service_amount, 'partner_id': request.family_id.partner_id.id,
'credit': 0.0, 'analytic_account_id': request.branch_custom_id.branch.analytic_account_id.id,
} 'debit': request.requested_service_amount,
) 'credit': 0.0,
total_credit += request.aid_amount }
)
total_credit += request.aid_amount
elif self.type == 'benefit_expense':
validation_setting = self.env["family.validation.setting"].search([], limit=1)
for line in self.benefit_expense_line_ids:
sum_line, credit_total = self._prepare_entry_lines(line, validation_setting)
total_credit += credit_total
lines += sum_line
lines.append({ lines.append({
'account_id': self.env["family.validation.setting"].search([], limit=1).account_id.id, 'account_id': self.journal_id.default_account_id.id,
'name': f'{self.name}-{self.ref_num}', 'name': f'{self.name}-{self.ref_num}',
'credit': total_credit, 'credit': total_credit,
'debit': 0.0, 'debit': 0.0,

View File

@ -9,6 +9,7 @@ from dateutil.relativedelta import relativedelta
class SeasonalService(models.Model): class SeasonalService(models.Model):
_name = 'seasonal.service' _name = 'seasonal.service'
_inherit = ['mail.thread', 'mail.activity.mixin'] _inherit = ['mail.thread', 'mail.activity.mixin']
_order = "name desc"
name = fields.Char(string='Reference', required=True, copy=False, readonly=True, index=True, name = fields.Char(string='Reference', required=True, copy=False, readonly=True, index=True,
default=lambda self: _('New')) default=lambda self: _('New'))
@ -204,6 +205,7 @@ class SeasonalService(models.Model):
'seasonal_requests_ids': rec.ids, 'seasonal_requests_ids': rec.ids,
'service_requests_ids': rec.service_requests_ids.ids, 'service_requests_ids': rec.service_requests_ids.ids,
'is_seasonal': True, 'is_seasonal': True,
'type': 'seasonal_services',
}) })
# rec.payment_order_id = payment_order.id # rec.payment_order_id = payment_order.id
rec.is_payment_order_done = True rec.is_payment_order_done = True
@ -272,6 +274,11 @@ class SeasonalService(models.Model):
rec.service_requests_ids.unlink() rec.service_requests_ids.unlink()
rec.state = 'draft' rec.state = 'draft'
def action_reset_to_calculated(self):
for rec in self:
rec.service_requests_ids.write({'state': 'draft'})
rec.state = 'calculated'
class SeasonalGrantBenefit(models.Model): class SeasonalGrantBenefit(models.Model):
_name = 'seasonal.grant.benefit' _name = 'seasonal.grant.benefit'

View File

@ -120,7 +120,7 @@ class ServiceRequest(models.Model):
# maintenance_items_id = fields.Many2one('home.maintenance.lines', string="Maintenance Items") # maintenance_items_id = fields.Many2one('home.maintenance.lines', string="Maintenance Items")
maintenance_items_ids = fields.One2many('home.maintenance.items', 'service_request_id', maintenance_items_ids = fields.One2many('home.maintenance.items', 'service_request_id',
string="Maintenance Items", ) string="Maintenance Items", )
payment_order_id = fields.Many2one('payment.orders', string='Payment Order', ondelete="set null") payment_order_id = fields.Many2one('payment.orders', string='Payment Order', ondelete="set null", copy=False)
is_payment_order_done = fields.Boolean(string='Is Payment Order Done?') is_payment_order_done = fields.Boolean(string='Is Payment Order Done?')
aid_amount = fields.Float(string='Aid Amount', compute='_get_aid_amount') aid_amount = fields.Float(string='Aid Amount', compute='_get_aid_amount')
# Fields for alternative house # Fields for alternative house
@ -129,7 +129,7 @@ class ServiceRequest(models.Model):
# Fields for electrical_devices service # Fields for electrical_devices service
device_id = fields.Many2one('electrical.devices', string='Device', device_id = fields.Many2one('electrical.devices', string='Device',
domain="[('min_count_member','<=',benefit_member_count),('max_count_member','>=',benefit_member_count)]") domain="[('min_count_member','<=',benefit_member_count),('max_count_member','>=',benefit_member_count)]")
vendor_bill = fields.Many2one('account.move') vendor_bill = fields.Many2one('account.move', copy=False)
requested_quantity = fields.Integer(string='Requested Quantity') requested_quantity = fields.Integer(string='Requested Quantity')
exception_or_steal = fields.Boolean(string='Exception Or Steal?') exception_or_steal = fields.Boolean(string='Exception Or Steal?')
exception_or_steal_attach = fields.Many2many('ir.attachment', 'rel_exception_or_steal_attachment_service_request', exception_or_steal_attach = fields.Many2many('ir.attachment', 'rel_exception_or_steal_attachment_service_request',
@ -146,10 +146,6 @@ class ServiceRequest(models.Model):
# ('programs_transportation', 'Programs Transportation'), # ('programs_transportation', 'Programs Transportation'),
# ], string='Service Reason') # ], string='Service Reason')
service_reason_id = fields.Many2one('transportation.insurance') service_reason_id = fields.Many2one('transportation.insurance')
# max_government_transportation_amount = fields.Float(string='Max Government Transportation Amount')
# max_universities_training_institutes_transportation_amount = fields.Float(string='Max Universities Training Institutes Transportation Amount')
# max_hospitals_transportation_amount = fields.Float(string='Max Hospitals Transportation Amount')
# max_programs_transportation_amount = fields.Float(string='Max Programs Transportation Amount')
max_amount = fields.Float(string='Max Transportation Amount') max_amount = fields.Float(string='Max Transportation Amount')
requests_counts = fields.Integer(string='Requests Counts', default=1) requests_counts = fields.Integer(string='Requests Counts', default=1)
# Marriage # Marriage
@ -222,13 +218,19 @@ class ServiceRequest(models.Model):
('waiting', 'Waiting Payment'), ('waiting', 'Waiting Payment'),
('done', 'Done Payment'), ], copy=False, compute="_compute_payment_order_state", store=True) ('done', 'Done Payment'), ], copy=False, compute="_compute_payment_order_state", store=True)
@api.depends('payment_order_id', 'payment_order_id.state') @api.depends('payment_order_id', 'payment_order_id.state', 'vendor_bill', 'vendor_bill.state')
def _compute_payment_order_state(self): def _compute_payment_order_state(self):
for rec in self: for rec in self:
payment_order_state = 'none' payment_order_state = 'none'
if rec.payment_order_state: if rec.payment_order_id:
if rec.payment_order_id.state == "done": if rec.payment_order_id.state == "done":
payment_order_state = "done" payment_order_state = "done"
rec.is_payment_order_done = True
else:
payment_order_state = "waiting"
elif rec.vendor_bill:
if rec.vendor_bill.state == "posted":
payment_order_state = "done"
else: else:
payment_order_state = "waiting" payment_order_state = "waiting"
rec.payment_order_state = payment_order_state rec.payment_order_state = payment_order_state
@ -974,59 +976,7 @@ class ServiceRequest(models.Model):
for rec in self: for rec in self:
rec.state = 'draft' rec.state = 'draft'
def action_open_exchange_order_wizard(self): def action_accounting_transfer(self):
ids = []
for rec in self:
ids.append(rec.id)
default_service_ids = ids
service_requests = self.env['service.request'].browse(ids)
if any(request.state not in 'send_request_to_supplier' for request in service_requests):
raise UserError(_("All selected requests should be in Accounting Approve state"))
if any(request.payment_order_id for request in service_requests):
raise UserError(_("All selected requests should be not has payment order"))
else:
return {
'type': 'ir.actions.act_window',
'name': 'Exchange Order',
'res_model': 'exchange.order.wizard',
'view_mode': 'form',
'target': 'new',
'context': {'default_service_ids': ids}
}
def action_create_payment_order(self):
service_cats = self.mapped('service_cat')
if len(service_cats) > 1:
cat_names = ", ".join(service_cats.mapped('service_name'))
raise UserError(_(
"All selected service requests must belong to the same Service Cat.\n\n"
"Selected Services Cat:\n%s"
) % cat_names)
invalid_records = self.filtered(
lambda r: r.state != 'accounting_approve'
or r.payment_order_state != 'none'
or r.payment_order_id
)
if invalid_records:
names = ", ".join(invalid_records.mapped('name'))
raise UserError(_(
"The following service requests do not meet the conditions:\n%s\n"
"Each request must:\n"
"• Be in 'Accounting Approve' state\n"
"• Have payment order state = 'None'\n"
"• Not be linked to any payment order"
) % names)
self.env['payment.orders'].create({
'state': 'draft',
'accountant_id': self[0].service_cat.accountant_id.id,
'service_requests_ids': [(6, 0, self.ids)],
})
self.write({'is_payment_order_done': True})
def create_vendor_bill(self):
line_ids = [] line_ids = []
service_cats = self.mapped('service_cat') service_cats = self.mapped('service_cat')
if len(service_cats) > 1: if len(service_cats) > 1:
@ -1036,39 +986,59 @@ class ServiceRequest(models.Model):
"Selected Services Cat:\n%s" "Selected Services Cat:\n%s"
) % cat_names) ) % cat_names)
service_cat = service_cats[0] if service_cats else False if service_cats.payment_method == "payment_order":
if service_cat and service_cat.service_type != 'electrical_devices': invalid_records = self.filtered(
raise UserError(_("Only 'Electrical Devices' service cat requests can create a invoice.")) lambda r: r.state != 'accounting_approve'
or r.payment_order_state != 'none'
or r.payment_order_id
)
invalid_records = self.filtered( if invalid_records:
lambda r: r.state != 'accounting_approve' names = ", ".join(invalid_records.mapped('name'))
or r.payment_order_state != 'none' raise UserError(_(
or r.payment_order_id "The following service requests do not meet the conditions:\n%s\n"
) "Each request must:\n"
"• Be in 'Accounting Approve' state\n"
"• Have payment order state = 'None'\n"
"• Not be linked to any payment order"
) % names)
if invalid_records: self.env['payment.orders'].create({
names = ", ".join(invalid_records.mapped('name')) 'state': 'draft',
raise UserError(_( 'accountant_id': service_cats.accountant_id.id,
"The following service requests do not meet the conditions:\n%s\n" 'service_requests_ids': [(6, 0, self.ids)],
"Each request must:\n" 'type': 'services',
"• Be in 'Accounting Approve' state\n"
"• Have payment order state = 'None'\n"
"• Not be linked to any payment order"
) % names)
for rec in self:
invoice_line = (0, 0, {
'name': f'{rec.family_id.name}/{rec.device_id.device_name}/{rec.description}/{rec.name}',
'account_id': rec.device_account_id.id,
'analytic_account_id': rec.branch_custom_id.branch.analytic_account_id.id,
'quantity': rec.requested_quantity,
'price_unit': rec.requested_service_amount,
}) })
line_ids.append(invoice_line) elif service_cats.payment_method == "invoice":
vendor_bill = self.env['account.move'].create({ invalid_records = self.filtered(
'move_type': 'in_invoice', lambda r: r.state != 'accounting_approve'
'partner_id': self[0].service_producer_id.id, or r.payment_order_state != 'none'
# 'accountant_id': self.accountant_id.id, or r.vendor_bill
'invoice_line_ids': line_ids, )
})
self.vendor_bill = vendor_bill if invalid_records:
names = ", ".join(invalid_records.mapped('name'))
raise UserError(_(
"The following service requests do not meet the conditions:\n%s\n"
"Each request must:\n"
"• Be in 'Accounting Approve' state\n"
"• Have payment order state = 'None'\n"
"• Not be linked to any invoice"
) % names)
for rec in self:
invoice_line = (0, 0, {
'name': f'{rec.family_id.name}/{rec.device_id.device_name}/{rec.description}/{rec.name}',
'account_id': rec.device_account_id.id,
'analytic_account_id': rec.branch_custom_id.branch.analytic_account_id.id,
'quantity': rec.requested_quantity,
'price_unit': rec.requested_service_amount,
})
line_ids.append(invoice_line)
vendor_bill = self.env['account.move'].create({
'move_type': 'in_invoice',
'partner_id': self[0].service_producer_id.id,
# 'accountant_id': self.accountant_id.id,
'invoice_line_ids': line_ids,
})
self.vendor_bill = vendor_bill

View File

@ -111,6 +111,11 @@ class ServicesSettings(models.Model):
help='Specify the maximum allowed number of months when the period type is monthly.' help='Specify the maximum allowed number of months when the period type is monthly.'
) )
in_kind = fields.Boolean(string="In Kind") in_kind = fields.Boolean(string="In Kind")
payment_method = fields.Selection([
('none', 'None'),
('payment_order', 'Payment Order'),
('invoice', 'Invoice'),
], string='Payment Method',default="payment_order")

View File

@ -17,6 +17,7 @@
<field name="family_monthly_meals"/> <field name="family_monthly_meals"/>
<field name="family_monthly_clotting"/> <field name="family_monthly_clotting"/>
<field name="total_family_expenses"/> <field name="total_family_expenses"/>
<field name="payment_order_id" invisible="1"/>
</tree> </tree>
</field> </field>
</record> </record>
@ -35,6 +36,7 @@
<field name="family_category_id"/> <field name="family_category_id"/>
<field name="meal_card"/> <field name="meal_card"/>
<field name="benefit_member_count"/> <field name="benefit_member_count"/>
<field name="payment_order_id" invisible="1"/>
</group> </group>
<group> <group>
<field name="family_monthly_income"/> <field name="family_monthly_income"/>

View File

@ -152,6 +152,7 @@
<field name="family_monthly_clotting" <field name="family_monthly_clotting"
attrs="{'column_invisible': [('parent.cloth_expense', '!=', True)]}"/> attrs="{'column_invisible': [('parent.cloth_expense', '!=', True)]}"/>
<field name="total_family_expenses"/> <field name="total_family_expenses"/>
<field name="payment_order_id" invisible="1"/>
</tree> </tree>
</field> </field>
</page> </page>

View File

@ -40,6 +40,7 @@
<field name="benefit_category_ids" widget="many2many_tags"/> <field name="benefit_category_ids" widget="many2many_tags"/>
<field name="journal_id"/> <field name="journal_id"/>
<field name="account_id" string="Service Payment Account"/> <field name="account_id" string="Service Payment Account"/>
<field name="accountant_id"/>
</group> </group>
</sheet> </sheet>
</form> </form>

View File

@ -24,6 +24,15 @@
states="waiting_gm" states="waiting_gm"
string="Approve" class="oe_highlight"/> string="Approve" class="oe_highlight"/>
<button name="create_entry" type="object"
string="Create Entry" class="oe_highlight"
attrs="{'invisible': ['|',('state','!=','waiting_deposit'),('move_id', '!=',False)]}"
/>
<button name="action_deposit" type="object"
string="Deposit Completed" class="oe_highlight"
attrs="{'invisible': ['|',('state','!=','waiting_deposit'),('move_id', '=',False)]}"
/>
<button name="action_refuse" type="object" <button name="action_refuse" type="object"
states="draft" states="draft"
@ -47,6 +56,7 @@
</div> </div>
<group> <group>
<field name="payment_order_date"/> <field name="payment_order_date"/>
<field name="type" readonly="1"/>
<field name="accountant_id"/> <field name="accountant_id"/>
<field name="journal_id"/> <field name="journal_id"/>
</group> </group>
@ -54,15 +64,15 @@
<field name="payment_order_description"/> <field name="payment_order_description"/>
<field name="ref_num"/> <field name="ref_num"/>
<field name="is_seasonal" invisible="1"/> <field name="is_seasonal" invisible="1"/>
<field name="move_id" attrs="{'invisible':[('move_id','=',False)]}"/>
</group> </group>
</group> </group>
<notebook> <notebook>
<page string="Services Requests"> <page string="Services Requests"
attrs="{'invisible':[('type','not in',['seasonal_services','services'])]}">
<field name="service_requests_ids" widget="one2many_list" <field name="service_requests_ids" widget="one2many_list"
readonly="1"> readonly="1">
<tree editable="bottom"> <tree>
<field name="family_id"/> <field name="family_id"/>
<field name="member_id"/> <field name="member_id"/>
<field name="branch_custom_id"/> <field name="branch_custom_id"/>
@ -73,11 +83,10 @@
</tree> </tree>
</field> </field>
</page> </page>
<page string="Seasonal Services" invisible="1">
<page string="Seasonal Services">
<field name="family_seasonal_requests_ids" widget="one2many_list" <field name="family_seasonal_requests_ids" widget="one2many_list"
readonly="1"> readonly="1">
<tree editable="bottom"> <tree>
<field name="family_id"/> <field name="family_id"/>
<field name="branch_custom_id"/> <field name="branch_custom_id"/>
<field name="account_id"/> <field name="account_id"/>
@ -87,6 +96,26 @@
</tree> </tree>
</field> </field>
</page> </page>
<page string="Confirm Benefit Expenses"
attrs="{'invisible':[('type','!=','benefit_expense')]}">
<field name="benefit_expense_line_ids" widget="one2many_list"
readonly="1">
<tree>
<field name="family_id"/>
<field name="branch_id"/>
<field name="family_category_id"/>
<field name="start_date" invisible="1"/>
<field name="end_date" invisible="1"/>
<field name="meal_card"/>
<field name="benefit_member_count"/>
<field name="family_monthly_income"/>
<field name="family_monthly_meals"/>
<field name="family_monthly_clotting"/>
<field name="total_family_expenses"/>
<field name="payment_order_id" invisible="1"/>
</tree>
</field>
</page>
</notebook> </notebook>
</sheet> </sheet>
<div class="oe_chatter"> <div class="oe_chatter">

View File

@ -24,12 +24,6 @@
string="Approve" class="oe_highlight" string="Approve" class="oe_highlight"
attrs="{'invisible': [('state', '!=', 'gm_assistant')]}"/> attrs="{'invisible': [('state', '!=', 'gm_assistant')]}"/>
<button name="action_accounting_approve" type="object"
string="Accounting Approve"
class="oe_highlight"
attrs="{'invisible': [('state', '!=', 'accounting_approve')]}"
groups="odex_benefit.group_benefit_accounting_accept"/>
<button name="action_create_payment_order" <button name="action_create_payment_order"
type="object" type="object"
string="امر الصرف" string="امر الصرف"
@ -37,6 +31,12 @@
attrs="{'invisible': ['|', ('state', '!=', 'accounting_approve'), ('payment_order_id', '!=', False)]}" attrs="{'invisible': ['|', ('state', '!=', 'accounting_approve'), ('payment_order_id', '!=', False)]}"
groups="odex_benefit.group_benefit_accounting_accept"/> groups="odex_benefit.group_benefit_accounting_accept"/>
<button name="action_reset_to_calculated" type="object"
string="Reset"
class="oe_highlight"
attrs="{'invisible': [('state', '!=', 'accounting_approve')]}"
/>
<field name="state" widget="statusbar" <field name="state" widget="statusbar"
statusbar_visible="draft,calculated,accounting_approve,waiting_receive,done"/> statusbar_visible="draft,calculated,accounting_approve,waiting_receive,done"/>
</header> </header>
@ -70,7 +70,7 @@
</group> </group>
<group> <group>
<field name="aid_amount"/> <field name="aid_amount" attrs="{'readonly': [('service_delivery_method', '=', 'cash')]}"/>
<field name="family_count" readonly="1"/> <field name="family_count" readonly="1"/>
<field name="benefit_member_count" readonly="1"/> <field name="benefit_member_count" readonly="1"/>
<field name="family_disbursement_total_amount" readonly="1"/> <field name="family_disbursement_total_amount" readonly="1"/>
@ -105,7 +105,8 @@
<field name="benefit_ids" domain="[('id', 'in', family_domain_ids)]"/> <field name="benefit_ids" domain="[('id', 'in', family_domain_ids)]"/>
</page> </page>
<page string="Members" attrs="{'invisible': [('benefit_type', '!=', 'member')]}"> <page string="Members" attrs="{'invisible': [('benefit_type', '!=', 'member')]}">
<field name="member_ids" domain="[('benefit_id', 'in', benefit_ids)]"/> <field name="member_ids" attrs="{'readonly': [('state', '!=', 'draft')]}"
domain="[('benefit_id', 'in', benefit_ids),('member_status', '=', 'benefit')]"/>
</page> </page>
</notebook> </notebook>
</sheet> </sheet>
@ -133,8 +134,18 @@
<field name="family_count"/> <field name="family_count"/>
<field name="benefit_member_count"/> <field name="benefit_member_count"/>
<field name="family_disbursement_total_amount"/> <field name="family_disbursement_total_amount"/>
<field name="state"/> <field name="state"
<field name="payment_order_state"/> widget="badge"
decoration-info="state == 'draft'"
decoration-warning="state not in ['draft','done']"
decoration-success="state == 'done'"
/>
<field name="payment_order_state"
widget="badge"
decoration-info="state == 'none'"
decoration-warning="state == 'waiting'"
decoration-success="state == 'done'"
/>
</tree> </tree>
</field> </field>
</record> </record>

View File

@ -159,9 +159,9 @@
<sheet> <sheet>
<field name="is_payment_order_done" invisible="1"/> <field name="is_payment_order_done" invisible="1"/>
<field name="payment_order_state" invisible="1"/> <field name="payment_order_state" invisible="1"/>
<widget name="web_ribbon" title="Payment Order Done" bg_color="bg-success" <widget name="web_ribbon" title="Payment Done" bg_color="bg-success"
attrs="{'invisible': [('payment_order_state', '!=', 'done')]}"/> attrs="{'invisible': [('payment_order_state', '!=', 'done')]}"/>
<widget name="web_ribbon" title="Payment Order Waiting" bg_color="bg-warning" <widget name="web_ribbon" title="Payment Waiting" bg_color="bg-warning"
attrs="{'invisible': [('payment_order_state', '!=', 'waiting')]}"/> attrs="{'invisible': [('payment_order_state', '!=', 'waiting')]}"/>
<group> <group>
<div class="oe_title"> <div class="oe_title">
@ -195,7 +195,7 @@
<field name="payment_order_id" readonly="1" <field name="payment_order_id" readonly="1"
groups="odex_benefit.group_benefit_accounting_accept" invisible="1"/> groups="odex_benefit.group_benefit_accounting_accept" invisible="1"/>
<field name="vendor_bill" readonly="1" <field name="vendor_bill" readonly="1"
attrs="{'invisible':[('service_type','!=','electrical_devices')]}"/> attrs="{'invisible':[('vendor_bill','=',False)]}"/>
<field name="is_service_producer" invisible="1"/> <field name="is_service_producer" invisible="1"/>
<field name="service_producer_id" <field name="service_producer_id"
attrs="{'invisible':[('is_service_producer','=',False)],'readonly':[('state','not in',['draft','researcher','waiting_approve'])]}"/> attrs="{'invisible':[('is_service_producer','=',False)],'readonly':[('state','not in',['draft','researcher','waiting_approve'])]}"/>

View File

@ -96,6 +96,7 @@
<group> <group>
<field name="account_id" <field name="account_id"
attrs="{'invisible':[('service_type', 'in', ['electrical_devices', 'transportation_insurance'])]}"/> attrs="{'invisible':[('service_type', 'in', ['electrical_devices', 'transportation_insurance'])]}"/>
<field name="payment_method"/>
</group> </group>
<group> <group>
<field name="accountant_id"/> <field name="accountant_id"/>