[ADD] odex25_benefit: ADD new branch

This commit is contained in:
younes 2025-11-25 12:17:22 +01:00
parent 5d1c97b367
commit ed54a5fc39
211 changed files with 58627 additions and 0 deletions

View File

@ -0,0 +1 @@
from . import models

View File

@ -0,0 +1,21 @@
{
'name': 'Odex25 empowerment management',
'description': 'This module empowerment management ',
'author': 'Expert Co. Ltd.',
'website': 'http://exp-sa.com',
'category': 'Odex25-Ensan activity',
'depends': ['mail','odex_benefit'],
'data': [
'security/security.xml',
'security/ir.model.access.csv',
'data/ir_sequence_data.xml',
'views/service_settings.xml',
'views/empowerment_management.xml',
'views/education_entity.xml',
],
'installable': True,
'auto_install': False
}

View File

@ -0,0 +1,13 @@
<odoo>
<record id="seq_empowerment_request" model="ir.sequence">
<field name="name">Level Code</field>
<field name="code">empowerment.request</field>
<field name="prefix">Empw/</field>
<field name="number_next">1</field>
<field name="number_increment">1</field>
<field name="padding">4</field>
</record>
</odoo>

View File

@ -0,0 +1,630 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * odex25_empowermentmanagement
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-03 00:50+0000\n"
"PO-Revision-Date: 2024-11-03 00:50+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: odex25_empowermentmanagement
#: model:ir.model,name:odex25_empowermentmanagement.model_hr_qualification_req
msgid "HR Qualification"
msgstr "المؤهلات العلمية"
#. module: odex25_empowermentmanagement
#: model:ir.model,name:odex25_empowermentmanagement.model_qualification_specification_req
msgid "Qualification Specification"
msgstr "تخصص المؤهل"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_qualification_specification_req__name
msgid "Name"
msgstr "الاسم"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_qualification_specification_req__type
msgid "Type"
msgstr "النوع"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields.selection,name:odex25_empowermentmanagement.selection__empowerment_qualification_specification_req__type__qualification
msgid "Qualification"
msgstr "مؤهل"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields.selection,name:odex25_empowermentmanagement.selection__qualification_specification_req__type__certificate
msgid "Certificate"
msgstr "شهادة"
#. module: odex25_empowermentmanagement
#: model:ir.model,name:odex25_empowermentmanagement.model_hr_qualification_name_req
msgid "HR Qualification Name"
msgstr "اسم المؤهل العلمي"
#. module: odex25_empowermentmanagement
#: model:ir.model,name:odex25_empowermentmanagement.model_hr_employee_history_req
msgid "HR Employee History"
msgstr "تاريخ الموظف"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_qualification_req__uni_name
msgid "University Name"
msgstr "اسم الجامعة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_qualification_req__prg_status
msgid "Program Status"
msgstr "حالة البرنامج"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_qualification_req__comp_date
msgid "Completion Date"
msgstr "تاريخ الانتهاء"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_qualification_req__contact_name
msgid "Contact Name"
msgstr "اسم جهة الاتصال"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_qualification_req__contact_phn
msgid "Contact Phone No"
msgstr "رقم هاتف جهة الاتصال"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_qualification_req__contact_email
msgid "Contact Email"
msgstr "البريد الإلكتروني لجهة الاتصال"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_qualification_req__country_name
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_employee_history_req__country
msgid "Country"
msgstr "الدولة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_qualification_name_req__name
msgid "Qualification"
msgstr "المؤهل العلمي"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_qualification_name_req__sequence
msgid "Sequence"
msgstr "التسلسل"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_qualification_name_req__parent_id
msgid "Upper Qualification"
msgstr "المؤهل الأعلى"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_qualification_req__qualification_id
msgid "Qualification Name"
msgstr "اسم المؤهل"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_qualification_req__qualification_degree
msgid "Qualification Degree"
msgstr "درجة المؤهل"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_qualification_req__qualification_specification_id
msgid "Qualification Specification"
msgstr "تخصص المؤهل"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_qualification_req__attachment
msgid "Attachment"
msgstr "المرفق"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_employee_history_req__employement_history
msgid "Employment History"
msgstr "تاريخ التوظيف"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_employee_history_req__position
msgid "Position"
msgstr "الوظيفة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_employee_history_req__employeer
msgid "Employeer"
msgstr "صاحب العمل"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_employee_history_req__salary
msgid "Salary"
msgstr "الراتب"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_employee_history_req__address
msgid "Address"
msgstr "العنوان"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_employee_history_req__date_from
msgid "Date From"
msgstr "من تاريخ"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_hr_employee_history_req__date_to
msgid "Date To"
msgstr "إلى تاريخ"
#. module: odex25_empowermentmanagement
#: model:ir.model,name:odex25_empowermentmanagement.model_empowerment_study_specialization
msgid "Study Specialization"
msgstr "تخصص الدراسة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_study_specialization__type
msgid "Study Type"
msgstr "تخصص الدراسة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields.selection,name:empowerment.study.specialization.type_bachelor
msgid "Bachelor"
msgstr "بكالريوس"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields.selection,name:empowerment.study.specialization.type_diploma
msgid "Diploma"
msgstr "دبلوم"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_study_specialization__universities_colleges
msgid "Universities / Colleges"
msgstr "الجامعات / الكليات"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_study_specialization__institutes_schools
msgid "Institute / School Name"
msgstr "اسم المعهد / المدرسة"
#. module: odex25_empowermentmanagement
#: model:ir.model,name:odex25_empowermentmanagement.model_empowerment_education_entity
msgid "Education Entity"
msgstr "vvالجهات التعليمية"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_education_entity__name
msgid "Entity Name"
msgstr "اسم الجهة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_education_entity__entity_type
msgid "Entity Type"
msgstr "نوع الجهة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields.selection,name:odex25_empowermentmanagement.selection__empowerment_education_entity__entity_type__university
msgid "University"
msgstr "جامعة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields.selection,name:odex25_empowermentmanagement.selection__empowerment_education_entity__entity_type__college
msgid "College"
msgstr "كلية"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields.selection,name:odex25_empowermentmanagement.selection__empowerment_education_entity__entity_type__institute
msgid "Institute"
msgstr "معهد"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields.selection,name:odex25_empowermentmanagement.selection__empowerment_education_entity__entity_type__school
msgid "School"
msgstr "مدرسة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_education_entity__study_specialization
msgid "Study Specialization"
msgstr "تخصص الدراسة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields.selection,name:odex25_empowermentmanagement.selection__empowerment_education_entity__study_specialization__bachelor
msgid "Bachelor"
msgstr "بكالريوس"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields.selection,name:odex25_empowermentmanagement.selection__empowerment_education_entity__study_specialization__diploma
msgid "Diploma"
msgstr "دبلوم"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_education_entity__specialization_id
msgid "Study Specialization"
msgstr "تخصص الدراسة"
#. module: odex25_empowermentmanagement
#: model:ir.model,name:odex25_empowermentmanagement.model_empowerment_qualification_course
msgid "Qualification Course"
msgstr "دورات التأهيل"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_qualification_course__name
msgid "Entity Name"
msgstr "اسم الجهة"
#. module: odex25_empowermentmanagement
#: model:ir.model,name:odex25_empowermentmanagement.model_empowerment_training_entity
msgid "Training Entities"
msgstr "جهات التدريب"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_training_entity__name
msgid "Entity Name"
msgstr "اسم الجهة"
#. module: odex25_empowermentmanagement
#: model:ir.model,name:odex25_empowermentmanagement.model_empowerment_project_funding_type
msgid "Project Funding Type"
msgstr "نوع تمويل المشاريع"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_project_funding_type__name
msgid "Entity Name"
msgstr " اسم الجهة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_services_settings__linked_to_department
msgid "Linked to Department"
msgstr "مرتبط بقسم"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,help:odex25_empowermentmanagement.field_services_settings__linked_to_department
msgid "Link the service to an HR department"
msgstr "ربط الخدمة بقسم في الموارد البشرية"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_services_settings__hr_department_id
msgid "Linked Department"
msgstr "القسم المرتبط"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_services_settings__manager_id
msgid "Manager"
msgstr "المدير"
#. module: odex25_empowermentmanagement
#: model:ir.model,name:odex25_empowermentmanagement.model_res_partner
msgid "Empowerment Beneficiary"
msgstr "شريك تمكين"
#. module: odex25_empowermentmanagement
#: model:ir.model,name:odex25_empowermentmanagement.model_empowerment_return_reason_wizard
msgid "Return Reason"
msgstr "سبب الإرجاع"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_return_reason_wizard__reason
msgid "Reason"
msgstr "السبب"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__name
msgid "Request Number"
msgstr "رقم الطلب"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__request_date
msgid "Request Date"
msgstr "تاريخ الطلب"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__creator_id
msgid "Creator"
msgstr "المُنشئ"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__date_from
msgid "Date From"
msgstr "التاريخ من"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__date_to
msgid "Date To"
msgstr "التاريخ الى"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__branch_id
msgid "Branch"
msgstr "الفرع"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__familye_id
msgid "Family"
msgstr "الأسرة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__member_ids
msgid "Family Member"
msgstr "أفراد الأسرة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__benefit_category_id
msgid "Family Category"
msgstr "فئة الاسرة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__relationship
msgid "Beneficiary Relationship"
msgstr "صفة المستفيد"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__identity_number
msgid "ID Number"
msgstr "رقم الهوية"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__sms_phone
msgid "Mobile Number"
msgstr "رقم الجوال"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__email
msgid "Email"
msgstr "البريد الالكترونى"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__nationality
msgid "Nationality"
msgstr "الجنسية"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__education_status
msgid "Education Status"
msgstr "الحالة التعليمية"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__has_car
msgid "Family Owns a Car?"
msgstr "الأسرة لديها سيارة؟"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__health_status
msgid "Health Status"
msgstr "الحالة الصحية"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__service_id
msgid "Service Item"
msgstr "بند الخدمة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__service_type
msgid "Service Type"
msgstr "نوع الخدمة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__service_item
msgid "Service Element"
msgstr "عنصر الخدمة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__study_specialization
msgid "Study Specialization"
msgstr "تخصص الدراسة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__university_id
msgid "University / College Name"
msgstr "اسم الجامعة / الكلية"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__institute_id
msgid "Institute / School Name"
msgstr "اسم المعهد / المدرسة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__intercession_type
msgid "Intercession Type"
msgstr "نوع الشفاعة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__request_entity_id
msgid "Requesting Entity"
msgstr "اسم جهة الطلب"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__training_type
msgid "Training Type"
msgstr "نوع التدريب"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__training_course_id
msgid "Qualification Course"
msgstr "دورة التأهيل"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__training_entity_id
msgid "Training Entity"
msgstr "جهة التدريب"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__training_intercession_type
msgid "Training Intercession Type"
msgstr "نوع شفاعة التدريب"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__project_funding_type_id
msgid "Project Funding Type"
msgstr "نوع تمويل المشروع"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__sponsor_id
msgid "Sponsor Name"
msgstr "اسم الكافل"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__sponsor_mobile
msgid "Sponsor Mobile"
msgstr "جوال الكافل"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__sponsor_identity
msgid "Sponsor Identity"
msgstr "هوية الكافل"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__sponsor_email
msgid "Sponsor Email"
msgstr "بريد الكافل"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__finance_request_entity_id
msgid "Finance Request Entity"
msgstr "جهة الطلب المالية"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__request_receiver_id
msgid "Request Receiver"
msgstr "الشخص المرسل اليه الطلب"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__description
msgid "Description"
msgstr "الشرح"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__state
msgid "Status"
msgstr "الحالة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields.selection,name:odex25_empowermentmanagement.selection__empowerment_request__state__draft
msgid "Draft"
msgstr "مسودة"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields.selection,name:odex25_empowermentmanagement.selection__empowerment_request__state__social_worker
msgid "Social Worker (Awaiting Execution)"
msgstr "اخصائى اجتماعى (بإنتظار تنفيذ الطلب)"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields.selection,name:odex25_empowermentmanagement.selection__empowerment_request__state__head_of_department
msgid "Head of Department"
msgstr "رئيس القسم"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields.selection,name:odex25_empowermentmanagement.selection__empowerment_request__state__branch_manager
msgid "Branch Manager"
msgstr "مدير الفرع"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields.selection,name:odex25_empowermentmanagement.selection__empowerment_request__state__finance
msgid "Finance Department"
msgstr "ادارة المالية"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields.selection,name:odex25_empowermentmanagement.selection__empowerment_request__state__approved
msgid "Approved"
msgstr "معتمد"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields.selection,name:odex25_empowermentmanagement.selection__empowerment_request__state__rejected
msgid "Rejected"
msgstr "مرفوض"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__reject_reason
msgid "Rejection/Return Reason"
msgstr "ccسبب الرفض/الارجاع"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__return_reason
msgid "Return Reason"
msgstr "سبب الارجاع"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__employment_history_ids
msgid "Employment History"
msgstr "الخبرة العملية"
#. module: odex25_empowermentmanagement
#: model:ir.model.fields,field_description:odex25_empowermentmanagement.field_empowerment_request__qualifiction_id
msgid "Qualifications"
msgstr "المؤهلات"
#. module: odex25_empowermentmanagement
#: model:ir.ui.menu,name:odex25_empowermentmanagement.menu_empowerment_root
msgid "Empowerment Management"
msgstr "إدارة التمكين"
#. module: odex25_empowermentmanagement
#: model:ir.ui.menu,name:odex25_empowermentmanagement.menu_services_settings
msgid "Services Settings"
msgstr "اعدادات الخدمات"
#. module: odex25_empowermentmanagement
#: model:ir.ui.menu,name:odex25_empowermentmanagement.menu_education_sp_action
msgid "Study Specialization"
msgstr "تخصص الدراسة"
#. module: odex25_empowermentmanagement
#: model:ir.ui.menu,name:odex25_empowermentmanagement.menu_action_qualification_course
msgid "Qualification Courses"
msgstr "دورات التأهيل"
#. module: odex25_empowermentmanagement
#: model:ir.ui.menu,name:odex25_empowermentmanagement.menu_action_empowerment_training_entity
msgid "Training Entities"
msgstr "جهات التدريب"
#. module: odex25_empowermentmanagement
#: model:ir.ui.menu,name:odex25_empowermentmanagement.menu_action_empowerment_project_funding_type
msgid "Project Funding Types"
msgstr "أنواع تمويل المشاريع"
#. module: odex25_empowermentmanagement
#: model:ir.ui.menu,name:odex25_empowermentmanagement.menu_action_qualification_specification
msgid "Qualification Specification"
msgstr "تخصص المؤهل"
#. module: odex25_empowermentmanagement
#: model:ir.model,name:odex25_empowermentmanagement.model_empowerment_request
msgid "Empowerment Request"
msgstr "طلبات التمكين"
#. module: odex25_empowermentmanagement
#: model:ir.ui.menu,name:odex25_empowermentmanagement.menu_empowerment_requests
msgid "Empowerment Requests"
msgstr "طلبات التمكين"
#. module: odex25_empowermentmanagement
#: model:ir.ui.menu,name:odex25_empowermentmanagement.menu_education_entities
#: model:ir.ui.menu,name:odex25_empowermentmanagement.menu_education_entities_action
msgid "Educational Entities"
msgstr "الجهات التعليمية"

View File

@ -0,0 +1,4 @@
from . import empowerment_management
from . import service_settings
from . import education_entity

View File

@ -0,0 +1,74 @@
from datetime import datetime, timedelta, date
from dateutil import relativedelta
from hijri_converter import convert
from num2words import num2words
from odoo import api, exceptions, fields, models, _
from odoo.exceptions import ValidationError, Warning
from odoo.tools.translate import _
class Qualification(models.Model):
_name = "hr.qualification.req"
_description = "HR Qualification"
_rec_name = "uni_name"
uni_name = fields.Many2one(
comodel_name="empowerment.education.entity", string="University Name", required=True
)
# col_name = fields.Many2one(comodel_name="hr.college", string="College Name")
prg_status = fields.Char(string="Program Status")
comp_date = fields.Date(string="Completion Date")
contact_name = fields.Char(string="Contact Name")
contact_phn = fields.Char(string="Contact Phone No")
contact_email = fields.Char(string="Contact Email")
country_name = fields.Many2one(comodel_name="res.country",string="Country")
qualification_degree = fields.Selection(
[
("weak", _("Weak")),
("good", _("Good")),
("very_good", _("Very Good")),
("excellent", _("Excellent")),
]
)
qualification_specification_id = fields.Many2one(
comodel_name="qualification.specification.req",
domain=[("type", "=", "qualification")],
)
# relation field
qualification_relation_name = fields.Many2one(comodel_name="hr.employee")
qualification_id = fields.Many2one(comodel_name="hr.qualification.name.req", string="Qualification Name")
attachment = fields.Binary(string="Attachment")
class QualificationSpecification(models.Model):
_name = "qualification.specification.req"
_description = "Qualification Specification"
name = fields.Char(string="Name")
type = fields.Selection(
selection=[("qualification", "Qualification"), ("certificate", "Certificate")],
string="Type")
class HrQualificationName(models.Model):
_name = "hr.qualification.name.req"
_description = "HR Qualification Name"
name = fields.Char(string="Qualification")
sequence = fields.Integer(string="Sequence")
parent_id = fields.Many2one(comodel_name="hr.qualification.name.req", string="Upper Qualification")
class HrEmployeeHistory(models.Model):
_name = "hr.employee.history.req"
_description = "HR Employee History"
employement_history = fields.Many2one(comodel_name="hr.employee")
name = fields.Char(string="Name",required=True)
position = fields.Char(string="Position",required=True)
employeer = fields.Char(string="Employeer",required=True)
salary = fields.Float(string="Salary",required=True)
address = fields.Char(string="Address",required=True)
date_from = fields.Date(string="Date From",)
date_to = fields.Date(string="Date To",)
country = fields.Many2one(string="Country",comodel_name="res.country")

View File

@ -0,0 +1,204 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
from datetime import datetime
from odoo.exceptions import UserError, ValidationError
class EmpowermentRequest(models.Model):
_name = 'empowerment.request'
_description = 'Empowerment Request'
_inherit = ['mail.thread', 'mail.activity.mixin']
name = fields.Char(string='Request Number', readonly=True, default='New')
request_date = fields.Datetime(string='Request Date', readonly=True, default=fields.Datetime.now)
creator_id = fields.Many2one('res.users', string='Creator', default=lambda self: self.env.user, readonly=True)
date_from = fields.Datetime(string='Date From')
date_to = fields.Datetime(string='Date To')
branch_id = fields.Many2one("branch.settings", string='Branch', domain="[('branch_type','=','branches')]")
# Beneficiary Family
familye_id = fields.Many2one('grant.benefit', string='Family')
member_ids = fields.One2many(
'family.member',
compute='_compute_family_members',
string='Family Member'
)
benefit_category_id = fields.Many2one(related='familye_id.benefit_category_id', string='Family Category', readonly=True)
relationship = fields.Char(string='Beneficiary Relationship', readonly=True)
identity_number = fields.Char(related='familye_id.id_number', string='ID Number', readonly=True)
sms_phone = fields.Char(related='familye_id.sms_phone', string='Mobile Number', readonly=True)
email = fields.Char(related='familye_id.email', string='Email', readonly=True)
nationality = fields.Many2one(relates='familye_id.nationality_id', string='Nationality', readonly=True)
education_status = fields.Selection(related='familye_id.education_status', string='Education Status', readonly=True)
has_car = fields.Boolean(related='familye_id.has_car', string='Family Owns a Car?', readonly=True)
health_status = fields.Selection(related='familye_id.health_status', string='Health Status')
# Service Info
service_id = fields.Many2one('services.settings', string='Service Item')
service_type = fields.Selection(related='service_id.service_type', store=True)
service_item = fields.Char(string="Service Element")
# Education Info
study_specialization = fields.Selection([
('bachelor', 'Bachelor'),
('diploma', 'Diploma')
], string='Study Specialization')
university_id = fields.Many2one('empowerment.education.entity', string='University / College Name', domain="[('study_specialization','=','bachelor')]")
institute_id = fields.Many2one('empowerment.education.entity', string='Institute / School Name', domain="[('study_specialization','=','diploma')]")
intercession_type = fields.Selection([
('transfer', 'Transfer'),
('move', 'Move'),
('discount', 'Discount'),
('exemption', 'Exemption'),
], string='Intercession Type')
request_entity_id = fields.Many2one('empowerment.education.entity', string='Requesting Entity')
# Training Info
training_type = fields.Selection([
('skill', 'Skill-based'),
('entrepreneurship', 'Entrepreneurship'),
('professional', 'Professional')
], string='Training Type')
training_course_id = fields.Many2one('empowerment.qualification.course', string='Qualification Course')
training_entity_id = fields.Many2one('empowerment.training.entity', string='Training Entity')
training_intercession_type = fields.Selection([
('new_acceptance', 'New Acceptance'),
('transfer', 'Transfer'),
('relocation', 'Relocation'),
('discount', 'Discount'),
('exemption', 'Exemption')
], string="Training Intercession Type")
# Funding Info
project_funding_type_id = fields.Many2one('project.funding.type', string='Project Funding Type')
sponsor_id = fields.Many2one('res.partner', string='Sponsor Name')
sponsor_mobile = fields.Char(related='sponsor_id.mobile', readonly=True)
sponsor_identity = fields.Char(related='sponsor_id.id_number', readonly=True)
sponsor_email = fields.Char(related='sponsor_id.email', readonly=True)
finance_request_entity_id = fields.Many2one('education.entity', string="Finance Request Entity")
# Receiver
request_receiver_id = fields.Many2one(
'res.partner',
string='Request Receiver',
domain="[('is_empowerment_receiver', '=', True)]"
)
description = fields.Text(string='Description')
# Request State
state = fields.Selection([
('draft', 'Draft'),
('social_worker', 'Social Worker (Awaiting Execution)'),
('head_of_department', 'Head of Department'),
('branch_manager', 'Branch Manager'),
('finance', 'Finance Department'),
('approved', 'Approved'),
('rejected', 'Rejected'),
], default='draft', string='Status', tracking=True)
reject_reason = fields.Text(string='Rejection/Return Reason')
return_reason = fields.Text(string='Return Reason')
employment_history_ids = fields.One2many(
comodel_name="hr.employee.history.req",
inverse_name="employement_history"
)
qualifiction_id = fields.One2many(
"hr.qualification.req",
"qualification_relation_name",
string="Qualifications"
)
def unlink(self):
for order in self:
if order.state not in ['draft']:
raise UserError(_('You cannot delete this record State not Draft'))
return super(EmpowermentRequest, self).unlink()
@api.model
def create(self, vals):
if vals.get('name', 'New') == 'New':
vals['name'] = self.env['ir.sequence'].next_by_code('empowerment.request') or 'New'
return super(EmpowermentRequest, self).create(vals)
def action_approve_social_worker(self):
for rec in self:
rec.state = 'social_worker'
def action_approve_head(self):
for rec in self:
rec.state = 'head_of_department'
def action_return_to_social_worker(self):
for rec in self:
rec.state = 'social_worker'
def action_approve_branch(self):
for rec in self:
rec.state = 'branch_manager'
def action_approve_finance(self):
for rec in self:
rec.state = 'finance'
def action_approve_final(self):
for rec in self:
rec.state = 'approved'
def action_reject(self):
for rec in self:
rec.state = 'rejected'
def action_return_to_draft(self):
# Open wizard to collect return reason - opens form view on 'empowerment.return.reason.wizard'
return {
'type': 'ir.actions.act_window',
'name': _('سبب الإرجاع'),
'view_mode': 'form',
'res_model': 'empowerment.return.reason.wizard',
'target': 'new',
'context': {'default_request_id': self.id}
}
@api.depends('familye_id')
def _compute_family_members(self):
for rec in self:
rec.member_ids = rec.familye_id.member_ids.ids if rec.familye_id else False
class ResPartner(models.Model):
_inherit = 'res.partner'
is_empowerment_receiver = fields.Boolean(string='Empowerment Beneficiary')
class EmpowermentReturnReasonWizard(models.TransientModel):
_name = 'empowerment.return.reason.wizard'
_description = 'Return Reason'
request_id = fields.Many2one('empowerment.request', string='Request')
reason = fields.Text(string='Reason', required=True)
def action_return(self):
self.ensure_one()
if self.request_id:
self.request_id.write({
'state': 'draft',
'return_reason': self.reason
})
# Close wizard window after saving
return {'type': 'ir.actions.act_window_close'}

View File

@ -0,0 +1,111 @@
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
class ServicesSettings(models.Model):
_inherit = 'services.settings' # Inherit existing model
linked_to_department = fields.Boolean(
string='Linked to Department',
help='Link the service to an HR department'
)
hr_department_id = fields.Many2one(
'hr.department', string='Linked Department'
)
manager_id = fields.Many2one(
'hr.employee', string='Manager',
)
service_type = fields.Selection(selection_add=[
('educational_care', 'خدمة الرعاية التعليمية'),
('bachelor_service', 'خدمة البكالريوس'),
('diploma_service', 'خدمة الدبلوم'),
('bachelor_intercession', 'خدمة شفاعة البكالريوس'),
('diploma_intercession', 'خدمة شفاعة الدبلوم'),
('training_service', 'خدمة التدريب'),
('training_intercession', 'خدمة شفاعة التدريب'),
('funding_service', 'خدمة التمويل'),
('project_funding_intercession', 'خدمة شفاعة تمويل المشاريع'),
('employment_service', 'خدمة التوظيف')
])
class HrDepartment(models.Model):
_inherit = 'hr.department'
service_link_id = fields.Many2one(
'services.settings', string='خدمة مرتبطة', readonly=True
)
class EmpowermentEducationEntity(models.Model):
_name = 'empowerment.education.entity'
_description = 'Education Entity'
name = fields.Char(string='Entity Name', required=True)
entity_type = fields.Selection(
[('university', 'University'), ('college', 'College'),
('institute', 'Institute'), ('school', 'School')],
string='Entity Type', required=True
)
study_specialization = fields.Selection(
[('bachelor', 'Bachelor'), ('diploma', 'Diploma')],
string='Study Specialization', required=True
)
specialization_id = fields.Many2one(
'empowerment.study.specialization', string='Study Specialization',
domain="[('type', '=', study_specialization)]",
)
_sql_constraints = [
('name_unique', 'unique(name)', 'اسم الجهة يجب أن يكون فريداً!'),
]
@api.onchange('entity_type')
def _onchange_entity_type(self):
if self.entity_type in ['university', 'college']:
self.study_specialization = 'bachelor'
elif self.entity_type in ['institute', 'school']:
self.study_specialization = 'diploma'
else:
self.study_specialization = False
# Reset specialization_id when entity_type changes
# self.specialization_id = False
class StudySpecialization(models.Model):
_name = 'empowerment.study.specialization'
_description = 'Study Specialization'
type = fields.Selection([
('bachelor', 'Bachelor'),
('diploma', 'Diploma')
], string='Study Type', required=True)
universities_colleges = fields.Char(string='Universities / Colleges')
institutes_schools = fields.Char(string='Institute / School Name')
class EmpowermentQualificationCourse(models.Model):
_name = 'empowerment.qualification.course'
_description = 'Qualification Course'
name = fields.Char(string='Entity Name', required=True)
class EmpowermentTrainingEntity(models.Model):
_name = 'empowerment.training.entity'
_description = 'Training Entities'
name = fields.Char(string='Entity Name', required=True)
class EmpowermentProjectFundingType(models.Model):
_name = 'empowerment.project.funding.type'
_description = 'Project Funding Type'
name = fields.Char(string='Entity Name', required=True)

View File

@ -0,0 +1,13 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_empowerment_education_entity,access_empowerment_education_entity,model_empowerment_education_entity,,1,1,1,1
access_empowerment_study_specialization,access_empowerment_study_specialization,model_empowerment_study_specialization,,1,1,1,1
access_empowerment_request,access_empowerment_request,model_empowerment_request,,1,1,1,1
access_empowerment_return_reason_wizard,access_empowerment_return_reason_wizard,model_empowerment_return_reason_wizard,,1,1,1,1
access_hr_qualification_name_req,access_hr_qualification_name_req,model_hr_qualification_name_req,,1,1,1,1
access_hr_employee_history_req,access_hr_employee_history_req,model_hr_employee_history_req,,1,1,1,1
access_qualification_specification_req,access_qualification_specification_req,model_qualification_specification_req,,1,1,1,1
access_hr_qualification_req,access_hr_qualification_req,model_hr_qualification_req,,1,1,1,1
access_empowerment_qualification_cours,access_empowerment_qualification_cours,model_empowerment_qualification_course,,1,1,1,1
access_empowerment_training_entity,access_empowerment_training_entity,model_empowerment_training_entity,,1,1,1,1
access_empowerment_project_funding_type,access_empowerment_project_funding_type,model_empowerment_project_funding_type,,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_empowerment_education_entity access_empowerment_education_entity model_empowerment_education_entity 1 1 1 1
3 access_empowerment_study_specialization access_empowerment_study_specialization model_empowerment_study_specialization 1 1 1 1
4 access_empowerment_request access_empowerment_request model_empowerment_request 1 1 1 1
5 access_empowerment_return_reason_wizard access_empowerment_return_reason_wizard model_empowerment_return_reason_wizard 1 1 1 1
6 access_hr_qualification_name_req access_hr_qualification_name_req model_hr_qualification_name_req 1 1 1 1
7 access_hr_employee_history_req access_hr_employee_history_req model_hr_employee_history_req 1 1 1 1
8 access_qualification_specification_req access_qualification_specification_req model_qualification_specification_req 1 1 1 1
9 access_hr_qualification_req access_hr_qualification_req model_hr_qualification_req 1 1 1 1
10 access_empowerment_qualification_cours access_empowerment_qualification_cours model_empowerment_qualification_course 1 1 1 1
11 access_empowerment_training_entity access_empowerment_training_entity model_empowerment_training_entity 1 1 1 1
12 access_empowerment_project_funding_type access_empowerment_project_funding_type model_empowerment_project_funding_type 1 1 1 1

View File

@ -0,0 +1,8 @@
<odoo>
<record id="group_emp_social_specialist" model="res.groups">
<field name="name">مدير ادارة التمكين</field>
<field name="category_id" ref="odex_benefit.module_category_benefit"/>
</record>
</odoo>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@ -0,0 +1,38 @@
<odoo>
<record id="view_qualification_specification_form" model="ir.ui.view">
<field name="name">qualification.specification.req.form</field>
<field name="model">qualification.specification.req</field>
<field name="arch" type="xml">
<form string="Qualification Specification">
<sheet>
<group>
<field name="name"/>
<field name="type"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_qualification_specification_tree" model="ir.ui.view">
<field name="name">qualification.specification.req.tree</field>
<field name="model">qualification.specification.req</field>
<field name="arch" type="xml">
<tree string="Qualification Specifications">
<field name="name"/>
<field name="type"/>
</tree>
</field>
</record>
<record id="action_qualification_specification" model="ir.actions.act_window">
<field name="name">Qualification Specifications</field>
<field name="res_model">qualification.specification.req</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="menu_action_qualification_specification" name="Qualification Specification" parent="odex25_empowermentmanagement.menu_education_entities" action="action_qualification_specification" sequence="12"/>
</odoo>

View File

@ -0,0 +1,383 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_empowerment_request_form" model="ir.ui.view">
<field name="name">empowerment.request.form</field>
<field name="model">empowerment.request</field>
<field name="arch" type="xml">
<form string="طلب تمكين">
<sheet>
<header>
<!-- Draft -->
<button string="اعتماد الاخصائى الاجتماعى" type="object" name="action_approve_social_worker" states="draft"/>
<button string="رفض" type="object" name="action_reject" states="draft,social_worker,head_of_department,branch_manager,finance"/>
<!-- Social Worker -->
<button string="اعتماد" type="object" name="action_approve_head" states="social_worker"/>
<button string="ارجاع لمسودة" type="object" name="action_return_to_draft" states="social_worker"/>
<!-- Head of Department -->
<button string="اعتماد" type="object" name="action_approve_branch" states="head_of_department"/>
<button string="ارجاع للاخصائى الاجتماعى" type="object" name="action_return_to_social_worker" states="head_of_department"/>
<!-- Branch Manager -->
<button string="اعتماد" type="object" name="action_approve_finance" states="branch_manager"/>
<!-- Finance -->
<button string="اعتماد" type="object" name="action_approve_final" states="finance"/>
<button string="ارجاع لمسودة" type="object" name="action_return_to_draft" states="finance"/>
<field name="state" widget="statusbar" />
</header>
<group string="معلومات عامة">
<field name="name"/>
<field name="request_date"/>
<field name="creator_id"/>
<field name="branch_id"/>
</group>
<group string="البيانات الشخصية">
<field name="familye_id"/>
<field name="relationship"/>
<field name="benefit_category_id"/>
<field name="identity_number"/>
<field name="sms_phone"/>
<field name="email"/>
<field name="nationality"/>
<field name="education_status"/>
<field name="has_car"/>
<field name="health_status" attrs="{'required': [('service_type', '=', 'employment')]}"/>
</group>
<group string="بيانات الخدمة">
<field name="service_id"/>
<field name="service_type"/>
<field name="service_item"/>
</group>
<group string="بيانات تعليمية" attrs="{'invisible': [('service_type', 'not in', [
'educational_care','bachelor_service','diploma_service',
'bachelor_intercession','diploma_intercession'])]}">
<field name="study_specialization"
/>
<field name="university_id" attrs="{'invisible': [('study_specialization', '!=', 'bachelor')]}"
/>
<field name="institute_id" attrs="{'invisible': [('study_specialization', '!=', 'diploma')]}
" />
<field name="intercession_type" />
<field name="request_entity_id" />
<field name="description" />
</group>
<group string="بيانات تدريبية" attrs="{'invisible': [('service_type', 'not in', ['training_service','training_intercession'])]}">
<field name="training_type" />
<field name="training_course_id" context="{'default_name': ''}"/>
<field name="training_entity_id" attrs="{'invisible': [('service_type', '!=', 'training_intercession')]}"/>
<field name="training_intercession_type" attrs="{'invisible': [('service_type', '!=', 'training_intercession')]}"/>
</group>
<group string="بيانات تمويل" attrs="{'invisible': [('service_type', 'not in', ['funding_service','project_funding_intercession'])]}">
<field name="project_funding_type_id" attrs="{'invisible': [('service_type', '!=', 'funding_service')]}"/>
<field name="sponsor_id" domain="[('branch_id', '=', branch_id)]"/>
<field name="sponsor_mobile" readonly="1"/>
<!-- commmint-->
<field name="sponsor_identity" readonly="1"/>
<field name="sponsor_email" readonly="1"/>
<!-- <field name="sponsor_communication_method" readonly="1"/>-->
<field name="finance_request_entity_id" context="{'default_name': ''}" attrs="{'invisible': [('service_type', '!=', 'project_funding_intercession')]}"/>
</group>
<group string="الجهة المستلمة للطلب">
<field name="request_receiver_id"
context="{'default_is_empowerment_receiver': True}"
options="{'no_open': False}"/>
</group>
<!-- commint domain="[('is_empowerment_receiver', '=', True)]"
context="{'default_is_empowerment_receiver': True}"-->
<group string="الإجراءات">
<field name="reject_reason" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="return_reason" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
</group>
<notebook string="بيانات احصائية">
<page string="الدورات التدريبية">
<field name="employment_history_ids" >
<tree>
<field name="name" />
<field name="position" />
<field name="salary" />
<field name="date_from" required="True"/>
<field name="date_to" required="True"/>
<field name="country" required="True"/>
</tree>
</field>
</page>
<page string=" الخبرات السابقة">
<field name="qualifiction_id"
editable="bottom">
<tree editable="bottom">
<field name="uni_name"/>
<!-- <field name="col_name"/>-->
<field name="qualification_id" />
<field name="qualification_specification_id"
context="{'default_type': 'qualification'}"/>
<field name="qualification_degree" />
<field name="comp_date"/>
<field name="country_name" />
<field name="attachment" widget="binary"/>
</tree>
</field>
</page>
<page string="بيانات المستفيد">
<field name="member_ids" widget="one2many_list"
readonly="0" edit="0" create="0">
<form string="Family Member">
<widget name="web_ribbon" title="Non Benefit Member" bg_color="bg-danger"
attrs="{'invisible': [('member_status', '!=', 'non_benefit')]}"/>
<widget name="web_ribbon" title="Benefit Member" bg_color="bg-success"
attrs="{'invisible': [('member_status', '!=', 'benefit')]}"/>
<sheet>
<group>
<label for="relationn" string="Relation"/>
<div>
<field name="relationn" class="oe_inline" nolabel="1"
attrs="{'readonly':[('parent.state','not in',['draft','new','complete_info'])]}"
options='{"no_open": True,"no_create_edit": True}'
/>
<field name="relation" class="oe_inline" nolabel="1" invisible="1"/>
</div>
</group>
<group>
<group>
<field placeholder="Name" name="name" class="oe_inline" readonly="1"
force_save="1" invisible="1"/>
<field name="is_mother" invisible="1"/>
<field name="member_first_name" force_save="1"
attrs="{'invisible':[('is_mother','=',True)],'required':[('is_mother','=',False)]}"/>
<field name="mother_first_name" force_save="1"
attrs="{'invisible':[('is_mother','=',False)],'required':[('is_mother','=',True)]}"/>
<field name="member_third_name" force_save="1"
attrs="{'invisible':[('is_mother','=',True)],'required':[('is_mother','=',False)]}"/>
<field name="mother_third_name" force_save="1"
attrs="{'invisible':[('is_mother','=',False)],'required':[('is_mother','=',True)]}"/>
<field name="member_id_number" />
<field name="is_dead"/>
<field name="death_certificate" widget="many2many_attachment_preview"
attrs="{'invisible':[('is_dead','=',False)]}"/>
<!-- <field name="gender" required="1"/>-->
<field name="member_location" force_save="1" invisible="1"/>
<field name="relationn_type" invisible="1"/>
<field name="member_location_conf" required="1" domain="[('location_type', '=', relationn_type in ['mother','replacement_mother'] and 'mother_location' or 'member')]"
options="{'no_create': True, 'no_create_edit': True}"/>
<field name="is_work" attrs="{'invisible':[('age','&lt;',18)]}"/>
<field name="member_income"
attrs="{'invisible':['|',('age','&lt;',18),('is_work','=',False)], 'required':[('is_work','=',True)]}"/>
<field name="salary_certificate" widget="many2many_attachment_preview" attrs="{'invisible':['|',('age','&lt;',18),('is_work','=',False)]}"/>
<field name="minor_siblings" readonly="1" force_save="1"/>
<field name="sponsor_id"/>
<field name="is_excluded_suspension" invisible="1" readonly="1" force_save="1"/>
<field name="member_status" readonly="1" widget="badge"
decoration-success="member_status == 'benefit'"
decoration-danger="member_status == 'non_benefit'"/>
</group>
<group>
<field name="member_second_name" force_save="1"
attrs="{'invisible':[('is_mother','=',True)],'required':[('is_mother','=',False)]}"/>
<field name="mother_second_name" force_save="1"
attrs="{'invisible':[('is_mother','=',False)],'required':[('is_mother','=',True)]}"/>
<field name="member_family_name" force_save="1"
attrs="{'invisible':[('is_mother','=',True)],'required':[('is_mother','=',False)]}"/>
<field name="mother_family_name" force_save="1"
attrs="{'invisible':[('is_mother','=',False)],'required':[('is_mother','=',True)]}"/>
<field name="benefit_id" invisible="1"/>
<field name="member_phone"
attrs="{'invisible':[('is_mother','=',True)]}"/>
<field name="birth_date" />
<field name="age" />
<field name="age_status"/>
<field name="is_married"
attrs="{'invisible':[('is_mother','=',True)]}"/>
<field name="marriage_certificate"
widget="many2many_attachment_preview"
attrs="{'invisible':['|',('is_mother','=',True),('is_married','=',False)]}"/>
<field name="mother_marital_conf"
attrs="{'invisible':[('is_mother','=',False)]}"
options="{'no_create': True, 'no_create_edit': True}"
groups="!odex_benefit.group_benefit_manager"/>
<field name="mother_location" invisible="1"/>
</group>
</group>
<notebook>
<page string="Hobbies">
<field name="hobbies_attachment_ids" widget="one2many_list">
<tree editable="bottom">
<field name="hobbies_id" required="1"/>
<field name="name"/>
<field name="datas" widget="binary"
filename="attachment_file_name"/>
<button name="action_preview_attachment" type="object"
string="Preview Attachment"/>
<field name="expiration_date"/>
<field name="attach_status"/>
<field name="member_id" invisible="1"/>
</tree>
</field>
</page>
<page string="Diseases">
<field name="diseases_attachment_ids" widget="one2many_list">
<tree editable="bottom">
<field name="diseases_id" required="1"/>
<field name="name"/>
<field name="datas" widget="binary"
filename="attachment_file_name"/>
<button name="action_preview_attachment" type="object"
string="Preview Attachment"/>
<field name="expiration_date"/>
<field name="attach_status"/>
<field name="member_id" invisible="1"/>
</tree>
</field>
</page>
<page string="Disabilities">
<field name="disabilities_attachment_ids" widget="one2many_list">
<tree editable="bottom">
<field name="disabilities_id" required="1"/>
<field name="name"/>
<field name="datas" widget="binary"
filename="attachment_file_name"/>
<button name="action_preview_attachment" type="object"
string="Preview Attachment"/>
<field name="expiration_date"/>
<field name="attach_status"/>
<field name="member_id" invisible="1"/>
</tree>
</field>
</page>
<page string="Education">
<h3>Education Status</h3>
<field name="member_education_status_ids" mode="tree,form"/>
</page>
<page string="Attachments">
<field name="attachment_ids" widget="one2many_list">
<tree editable="bottom" delete="0">
<field name="name" string="Attachment Name"
attrs="{'readonly':[('is_default','=',True)]}"
force_save="1"/>
<field name="attach_id" invisible="1"/>
<field name="datas" widget="binary"
filename="attachment_file_name"/>
<button name="action_preview_attachment" type="object"
string="Preview Attachment"/>
<field name="expiration_date"/>
<field name="attach_status"/>
<field name="allow_days"/>
<field name="benefit_id" invisible="1"/>
<field name="is_required" invisible="1"/>
<field name="is_default" invisible="1"/>
</tree>
</field>
<group>
<field name="state" invisible="1"/>
<field name="required_attach"
attrs="{'required':[('state','not in',['draft','new'])]}"/>
</group>
</page>
</notebook>
</sheet>
</form>
<tree string="Family Members">
<field name="name" force_save="1"/>
<!-- <field name="gender" required="1"/>-->
<field name="relationn"/>
<field name="member_location_conf"/>
<field name="member_status" string="Is Benefit?"/>
<field name="age"/>
<field name="benefit_id"/>
<field name="state"/>
</tree>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="view_empowerment_request_tree" model="ir.ui.view">
<field name="name">empowerment.request.tree</field>
<field name="model">empowerment.request</field>
<field name="arch" type="xml">
<tree string="طلبات التمكين">
<field name="name"/>
<field name="familye_id"/>
<field name="service_id"/>
<field name="state"/>
</tree>
</field>
</record>
<record id="view_empowerment_request_search" model="ir.ui.view">
<field name="name">empowerment.request.search</field>
<field name="model">empowerment.request</field>
<field name="arch" type="xml">
<search string="بحث طلبات التمكين">
<!-- Search fields -->
<field name="name" string="رقم الطلب"/>
<field name="familye_id" string="المستفيد" options="{'no_create': True}"/>
<field name="sms_phone" string="رقم الجوال"/>
<field name="identity_number" string="رقم الهوية"/>
<!-- Group by / Aggregation filters -->
<filter string="نوع الخدمة" name="group_by_service_type" context="{'group_by':'service_type'}"/>
<filter string="بند الخدمة" name="group_by_service_id" context="{'group_by':'service_id'}"/>
<filter string="الحالة" name="group_by_state" context="{'group_by':'state'}"/>
</search>
</field>
</record>
<record id="action_empowerment_request" model="ir.actions.act_window">
<field name="name">طلبات التمكين</field>
<field name="res_model">empowerment.request</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_empowerment_request_search"/>
</record>
<record id="view_empowerment_return_reason_wizard_form" model="ir.ui.view">
<field name="name">empowerment.return.reason.wizard.form</field>
<field name="model">empowerment.return.reason.wizard</field>
<field name="arch" type="xml">
<form string="سبب الإرجاع">
<sheet>
<group>
<field name="reason" />
</group>
<footer>
<button string="حفظ" type="object" name="action_return" class="btn-primary"/>
<button string="إلغاء" class="btn-secondary" special="cancel"/>
</footer>
</sheet>
</form>
</field>
</record>
<menuitem id="menu_empowerment_requests" name="Empowerment Requests" parent="odex25_empowermentmanagement.menu_empowerment_root" action="action_empowerment_request"/>
</odoo>

View File

@ -0,0 +1,226 @@
<odoo>
<!-- Inherited form view to add linked_to_department and hr_department_id -->
<record id="view_services_settings_form_inherit_empowerment" model="ir.ui.view">
<field name="name">services.settings.form.empowerment</field>
<field name="model">services.settings</field>
<field name="inherit_id" ref="odex_benefit.services_settings_form"/> <!-- Adjust ref to actual base form -->
<field name="arch" type="xml">
<xpath expr="//sheet/group[1]" position="after">
<group>
<field name="linked_to_department" />
<field name="hr_department_id"/>
<field name="manager_id" />
</group>
</xpath>
</field>
</record>
<!-- Tree view for services.settings, extended -->
<record id="view_services_settings_tree_inherit_empowerment" model="ir.ui.view">
<field name="name">services.settings.tree.empowerment</field>
<field name="model">services.settings</field>
<field name="inherit_id" ref="odex_benefit.services_settings_tree"/>
<field name="arch" type="xml">
<xpath expr="//tree" position="inside">
<field name="linked_to_department"/>
<field name="hr_department_id"/>
</xpath>
</field>
</record>
<!-- View for Empowerment Education Entity -->
<record id="view_empowerment_education_entity_form" model="ir.ui.view">
<field name="name">empowerment.education.entity.form</field>
<field name="model">empowerment.education.entity</field>
<field name="arch" type="xml">
<form string="الجهات التعليمية">
<sheet>
<group>
<field name="name"/>
<field name="entity_type"/>
<field name="specialization_id"/>
<field name="study_specialization"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_empowerment_education_entity_tree" model="ir.ui.view">
<field name="name">empowerment.education.entity.tree</field>
<field name="model">empowerment.education.entity</field>
<field name="arch" type="xml">
<tree string="الجهات التعليمية">
<field name="name"/>
<field name="entity_type"/>
<field name="specialization_id"/>
<!-- <field name="study_specialization"/>-->
</tree>
</field>
</record>
<!-- Action menu for Education Entities -->
<record id="action_empowerment_education_entity" model="ir.actions.act_window">
<field name="name">الجهات التعليمية</field>
<field name="res_model">empowerment.education.entity</field>
<field name="view_mode">tree,form</field>
</record>
<record id="view_study_specialization_form" model="ir.ui.view">
<field name="name">empowerment.study.specialization.form</field>
<field name="model">empowerment.study.specialization</field>
<field name="arch" type="xml">
<form string="تخصص الدراسة">
<sheet>
<group>
<field name="type"/>
<field name="universities_colleges"
attrs="{'invisible': [('type', '!=', 'bachelor')]}"
/>
<field name="institutes_schools"
attrs="{'invisible': [('type', '!=', 'diploma')]}"
/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_study_specialization" model="ir.actions.act_window">
<field name="name">تخصص الدراسة</field>
<field name="res_model">empowerment.study.specialization</field>
<field name="view_mode">tree,form</field>
</record>
<record id="view_qualification_course_tree" model="ir.ui.view">
<field name="name">empowerment.qualification.course.tree</field>
<field name="model">empowerment.qualification.course</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
</tree>
</field>
</record>
<!-- Form View -->
<record id="view_qualification_course_form" model="ir.ui.view">
<field name="name">empowerment.qualification.course.form</field>
<field name="model">empowerment.qualification.course</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="name"/>
</group>
</sheet>
</form>
</field>
</record>
<!-- Action -->
<record id="action_qualification_course" model="ir.actions.act_window">
<field name="name">دورات التأهيل</field>
<field name="res_model">empowerment.qualification.course</field>
<field name="view_mode">tree,form</field>
</record>
<!-- Training Entity Views -->
<record id="view_empowerment_training_entity_tree" model="ir.ui.view">
<field name="name">empowerment.training.entity.tree</field>
<field name="model">empowerment.training.entity</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
</tree>
</field>
</record>
<record id="view_empowerment_training_entity_form" model="ir.ui.view">
<field name="name">empowerment.training.entity.form</field>
<field name="model">empowerment.training.entity</field>
<field name="arch" type="xml">
<form string="جهات التدريب">
<sheet>
<group>
<field name="name"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_empowerment_training_entity" model="ir.actions.act_window">
<field name="name">جهات التدريب</field>
<field name="res_model">empowerment.training.entity</field>
<field name="view_mode">tree,form</field>
</record>
<record id="view_empowerment_project_funding_type_tree" model="ir.ui.view">
<field name="name">empowerment.project.funding.type.tree</field>
<field name="model">empowerment.project.funding.type</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
</tree>
</field>
</record>
<record id="view_empowerment_project_funding_type_form" model="ir.ui.view">
<field name="name">empowerment.project.funding.type.form</field>
<field name="model">empowerment.project.funding.type</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="name"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_empowerment_project_funding_type" model="ir.actions.act_window">
<field name="name">أنواع تمويل المشاريع</field>
<field name="res_model">empowerment.project.funding.type</field>
<field name="view_mode">tree,form</field>
</record>
<!-- inherit department-->
<record id="view_hr_dep_form_inherit_empowerment" model="ir.ui.view">
<field name="name">hr.department.form.empowerment</field>
<field name="model">hr.department</field>
<field name="inherit_id" ref="hr.view_department_form"/> <!-- Adjust ref to actual base form -->
<field name="arch" type="xml">
<xpath expr="//field[@name='analytic_account_id']" position="after">
<field name="service_link_id" readonly="1" />
</xpath>
</field>
</record>
<!-- Menu -->
<menuitem id="menu_empowerment_root" name="Empowerment Management" groups="odex25_empowermentmanagement.group_emp_social_specialist" web_icon="odex25_empowermentmanagement,static/description/icon.png" />
<menuitem id="menu_services_settings" name="Services Settings" parent="menu_empowerment_root" sequence="10"/>
<menuitem id="menu_education_entities" name="Educational Entities" parent="menu_empowerment_root" sequence="20"/>
<!-- Link Actions -->
<menuitem id="menu_education_entities_action" name="Educational Entities" parent="menu_education_entities" action="action_empowerment_education_entity" sequence="10"/>
<menuitem id="menu_education_sp_action" name="Study Specialization" parent="menu_education_entities" action="action_study_specialization" sequence="11"/>
<menuitem id="menu_action_qualification_course" name="Qualification Courses" parent="menu_education_entities" action="action_qualification_course" sequence="13"/>
<menuitem id="menu_action_empowerment_training_entity" name="Training Entities" parent="menu_education_entities" action="action_empowerment_training_entity" sequence="14"/>
<menuitem id="menu_action_empowerment_project_funding_type" name="Project Funding Types" parent="menu_education_entities" action="action_empowerment_project_funding_type" sequence="15"/>
</odoo>

View File

@ -0,0 +1 @@
from . import models

View File

@ -0,0 +1,21 @@
{
'name': 'Odex25 Activity Custom',
'description': 'This module extends Real Estate module by adding new fields and menu for waqf owners',
'author': 'Expert Co. Ltd.',
'website': 'http://exp-sa.com',
'category': 'Odex25-Ensan activity',
'depends': ['mail','odex_benefit'],
'data': [
'security/security.xml',
'security/ir.model.access.csv',
'data/ir_sequence_data.xml',
'views/program.xml',
],
'installable': True,
'auto_install': False
}

View File

@ -0,0 +1,65 @@
<odoo>
<record id="seq_pa_program_level" model="ir.sequence">
<field name="name">Level Code</field>
<field name="code">pa.program.level</field>
<field name="prefix">LVL/</field>
<field name="number_next">1</field>
<field name="number_increment">1</field>
<field name="padding">4</field>
</record>
<record id="seq_pa_program_track" model="ir.sequence">
<field name="name">Track Code</field>
<field name="code">pa.program.track</field>
<field name="prefix">TRK/</field>
<field name="number_next">1</field>
<field name="number_increment">1</field>
<field name="padding">4</field>
</record>
<record id="seq_pa_program" model="ir.sequence">
<field name="name">Program Code</field>
<field name="code">pa.program</field>
<field name="prefix">PRG/</field>
<field name="number_next">1</field>
<field name="number_increment">1</field>
<field name="padding">4</field>
</record>
<record id="seq_pa_program_activity" model="ir.sequence">
<field name="name">Activity Code</field>
<field name="code">pa.program.activity</field>
<field name="prefix">ACT/</field>
<field name="number_next">1</field>
<field name="number_increment">1</field>
<field name="padding">4</field>
</record>
<record id="seq_pa_program_medad" model="ir.sequence">
<field name="name">Medad Code</field>
<field name="code">pa.program.medad</field>
<field name="prefix">MD/</field>
<field name="number_next">1</field>
<field name="number_increment">1</field>
<field name="padding">4</field>
</record>
<!-- <record id="seq_pa_program_registration" model="ir.sequence">-->
<!-- <field name="name">Registration Code</field>-->
<!-- <field name="code">pa.program.registration</field>-->
<!-- <field name="prefix">PA/</field>-->
<!-- <field name="number_next">1</field>-->
<!-- <field name="number_increment">1</field>-->
<!-- <field name="padding">4</field>-->
<!-- </record>-->
<record id="seq_pa_program_activity_registration" model="ir.sequence">
<field name="name">Program Activity Registration Code</field>
<field name="code">pa.program.activity.registration</field>
<field name="prefix">PA/</field>
<field name="number_next">1</field>
<field name="number_increment">1</field>
<field name="padding">4</field>
</record>
</odoo>

View File

@ -0,0 +1,703 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * odex25_program_activity
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-10-22 12:14+0000\n"
"PO-Revision-Date: 2024-10-22 15:14+0300\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: ar\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5);\n"
"X-Generator: Poedit 3.5\n"
#. module: odex25_program_activity
#: model:ir.model,name:odex25_program_activity.model_pa_program
msgid "Programs Screen"
msgstr "شاشة البرامج"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program__code
msgid "Program Code"
msgstr "كود البرنامج"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program__name
msgid "Program Name"
msgstr "اسم البرنامج"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program__payment_type
msgid "Payment Type"
msgstr "نوع الدفع"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program__payment_type__paid
msgid "Paid"
msgstr "مدفوع"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program__payment_type__unpaid
msgid "Unpaid"
msgstr "غير مدفوع"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program__sponsor_id
msgid "Linked Sponsor"
msgstr "الكافل المرتبط"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program__sponsor_support_amount
msgid "Allocated Support Amount"
msgstr "المبلغ المخصص للدعم"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program__budget
msgid "Program Budget"
msgstr "الموازنة المخصصة للبرنامج"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program__location
msgid "Program Location"
msgstr "موقع البرنامج"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program__location__inside
msgid "Internal"
msgstr "داخلي"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program__location__outside
msgid "External"
msgstr "خارجي"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program__description
msgid "Program Description"
msgstr "وصف البرنامج"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program__track_id
msgid "Associated Track"
msgstr "المسار المرتبط بالبرنامج"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program__analytic_account_id
msgid "Linked Analytic Account"
msgstr "الحساب التحليلي المرتبط"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program__estimated_budget
msgid "Associated Estimated Budget"
msgstr "الموازنة التقديرية المرتبطة"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program__active
msgid "Program Status"
msgstr "حالة البرنامج"
#. module: odex25_program_activity
#: model:ir.model,name:odex25_program_activity.model_pa_program_activity
msgid "Program Activity"
msgstr "نشاط البرنامج"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity__code
msgid "Activity Code"
msgstr "كود النشاط"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity__name
msgid "Activity Name"
msgstr "اسم النشاط"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity__description
msgid "Activity Description"
msgstr "وصف النشاط"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity__program_id
msgid "Related Program"
msgstr "البرنامج المرتبط"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity__location
msgid "Activity Location"
msgstr "موقع النشاط"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection_pa_program_activity_location_inside
msgid "Inside"
msgstr "داخلي"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection_pa_program_activity_location_outside
msgid "Outside"
msgstr "خارجي"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity__date_start
msgid "Activity Start Date"
msgstr "تاريخ بداية النشاط"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity__date_end
msgid "Activity End Date"
msgstr "تاريخ انتهاء النشاط"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity__analytic_account_id
msgid "Analytic Account"
msgstr "الحساب التحليلي المرتبط"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity__estimated_budget
msgid "Estimated Budget"
msgstr " الموازنة التقديرية المرتبطة"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity__active
msgid "Active"
msgstr "نشط"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_medad__code
msgid "Medad Code"
msgstr "كود مداد"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_medad__name
msgid "Medad Name"
msgstr "اسم المداد"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_medad__description
msgid "Medad Description"
msgstr "ccوصف المداد"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_medad__medad_type
msgid "Medad Type"
msgstr "نوع مداد"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_medad__medad_type__skills
msgid "Skills"
msgstr "مهارات"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_medad__medad_type__training
msgid "Training"
msgstr "تدريب"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_medad__medad_type__innovation
msgid "Innovation Support"
msgstr "دعم ابتكار"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_medad__activity_id
msgid "Associated Activity"
msgstr "النشاط المرتبط"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_medad__analytic_account_id
msgid "Associated Analytic Account"
msgstr "الحساب التحليلي المرتبط"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_medad__estimated_budget
msgid "Estimated Budget"
msgstr "الموازنة التقديرية المرتبطة"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_medad__active
msgid "Active"
msgstr "نشط"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_return_reason_wizard__registration_id
msgid "Registration Request"
msgstr "طلب التسجيل"
#. module: odex25_program_activity
#: model:ir.model,name:odex25_program_activity.model_pa_return_reason_wizard
msgid "Return Reason Wizard"
msgstr "معالج سبب الإرجاع"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_track__code
msgid "Track Code"
msgstr "كود المسار"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_track__name
msgid "Track Name"
msgstr "اسم المسار"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_track__description
msgid "Track Description"
msgstr "وصف المسار"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_track__branch
msgid "Branch"
msgstr "الفرع"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_track__gender
msgid "Gender"
msgstr "الجنس"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_track__gender__male
msgid "Male"
msgstr "ذكر"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_track__gender__female
msgid "Female"
msgstr "انثى"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_track__age_category
msgid "Age Category"
msgstr "الفئة العمرية"
#. module: odex25_program_activity
#: model:ir.model.fields,help:odex25_program_activity.field_pa_program_track__age_category
msgid "Filter track based on age category"
msgstr "تصفية المسار على حسب الفئة العمرية"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_track__study_category
msgid "Study Category"
msgstr "الفئة الدراسية"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_track__hobby
msgid "Hobby"
msgstr "الهواية"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_track__study_status
msgid "Study Status"
msgstr "الحالة الدراسية"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_track__health_status
msgid "Health Status"
msgstr "الحالة الصحية"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_track__education_status
msgid "Educational Status"
msgstr "الحالة التعليمية"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_track__partner_id
msgid "Associated Partner"
msgstr "الشريك المرتبط"
#. module: odex25_program_activity
#: model:ir.model.fields,help:odex25_program_activity.field_pa_program_track__partner_id
msgid "The partner linked to the track"
msgstr "الشريك المرتبط بالمسار"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_track__active
msgid "Track Status"
msgstr "حالة المسار"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_track__level_id
msgid "Associated Level"
msgstr "المستوى المرتبط"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__name
msgid "Request Number"
msgstr "رقم الطلب"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__request_date
msgid "Request Date"
msgstr "تاريخ الطلب"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__creator_id
msgid "Creator"
msgstr "المنشئ"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__date_from
msgid "Date From"
msgstr "التاريخ من"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__date_to
msgid "Date To"
msgstr "التاريخ الى"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__familye_id
msgid "Family"
msgstr "الأسرة"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__benefit_category_id
msgid "Family Category"
msgstr " فئة الأسرة"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__sms_phone
msgid "Mobile Number"
msgstr "رقم الجوال"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__member_ids
msgid "Family Members"
msgstr "أفراد الأسرة"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__branch_custom_id
msgid "Branch"
msgstr "الفرع"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__gender
msgid "Gender"
msgstr "الجنس"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__nationality_id
msgid "Nationality"
msgstr "الجنسية"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__graduation_status
msgid "Graduation Status"
msgstr "الحالة الدراسية"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__health_status
msgid "Health Status"
msgstr "الحالة الصحية"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__education_status
msgid "Educational Status"
msgstr "الحالة التعليمية"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__mother_is_life
msgid "Is Mother Alive?"
msgstr "هل الأم على قيد الحياة؟"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__mother_location_conf
msgid "Mother Location"
msgstr "سكن الأم"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__is_mother_work
msgid "Is Mother Working?"
msgstr "هل الأم تعمل؟"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__housing_type
msgid "Housing Type"
msgstr "نوع السكن"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__beneficiary_relation
msgid "Beneficiary Relation"
msgstr "الجهة المستفيدة"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_activity_registration__beneficiary_relation__mother
msgid "Mother"
msgstr "أم"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_activity_registration__beneficiary_relation__son
msgid "Son"
msgstr "ابن"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_activity_registration__beneficiary_relation__daughter
msgid "Daughter"
msgstr "ابنه"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__beneficiary_ids
msgid "Beneficiary Name"
msgstr "اسم المستفيد"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__sons
msgid "Number of Sons"
msgstr "عدد الأولاد"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__daughters
msgid "Number of Daughters"
msgstr "عدد البنات"
#. module: odex25_program_activity
#: model:ir.model,name:odex25_program_activity.model_pa_program_level
msgid "pa.program.level"
msgstr "شاشة المستويات (Levels)"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_level__code
msgid "Level Code"
msgstr "كود المستوى"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_level__name
msgid "Level Name"
msgstr "اسم المستوى"
#. module: odex25_program_activity
#: model:ir.model.fields,help:odex25_program_activity.field_pa_program_level__name
msgid "Enter the level name such as: cultural, cognitive, religious, developmental, preventive, therapeutic"
msgstr "اكتب اسم المستوى مثل: ثقافية، معرفية، دينية، تنموية، وقائية، علاجية"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_level__type
msgid "Level Type"
msgstr "نوع المستوى"
#. module: odex25_program_activity
#: model:ir.model.fields,help:odex25_program_activity.field_pa_program_level__type
msgid "Select the type of level"
msgstr "حدد نوع المستوى"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_level__description
msgid "Level Description"
msgstr "وصف المستوى"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_level__active
msgid "Level Status"
msgstr "حالة المستوى"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_level__track_ids
msgid "Associated Tracks"
msgstr "المسارات المرتبطة"
#. module: odex25_program_activity
#: model:ir.model.fields,help:odex25_program_activity.field_pa_program_level__track_ids
msgid "Tracks that belong to this level"
msgstr "المسارات التي تنتمي إلى هذا المستوى"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program__program_type_id
msgid "Program Type"
msgstr "نوع البرنامج"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_type__pg_type
msgid "Name"
msgstr "نوع البرنامج"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_level__type__route
msgid "Tracks"
msgstr "مسارات "
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_level__type__activity
msgid "Activities"
msgstr "أنشطة"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_level__type__medad
msgid "Medad"
msgstr "مداد"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_family_member__need_trans
msgid "Need Transportation"
msgstr " هل يحتاج إلى مواصلات؟"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_family_member__need_medicin
msgid "Need Medicien"
msgstr "هل يتناول ادوية "
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_family_member__need_mental_dis
msgid "Have Mental Disorders"
msgstr " هل يوجد شخص فى الاسرة لديه اضطرابات نفسية"
#. module: odex25_program_activity
#: model:ir.ui.menu,name:odex25_program_activity.menu_pa_root
msgid "Programs and Activities"
msgstr "البرامج والأنشطة"
#. module: odex25_program_activity
#: model:ir.ui.menu,name:odex25_program_activity.menu_pa_registration
msgid "Activity Registration"
msgstr "تسجيل الأنشطة"
#. module: odex25_program_activity
#: model:ir.ui.menu,name:odex25_program_activity.menu_pa_settings
msgid "Settings"
msgstr "الإعدادات"
#. module: odex25_program_activity
#: model:ir.ui.menu,name:odex25_program_activity.menu_pa_levels
msgid "Program Levels"
msgstr "مستويات البرامج"
#. module: odex25_program_activity
#: model:ir.ui.menu,name:odex25_program_activity.menu_pa_tracks
msgid "Program Tracks"
msgstr "مسارات البرامج"
#. module: odex25_program_activity
#: model:ir.ui.menu,name:odex25_program_activity.menu_pa_programs
msgid "Programs"
msgstr "البرامج"
#. module: odex25_program_activity
#: model:ir.ui.menu,name:odex25_program_activity.menu_pa_program_type
msgid "Program Types"
msgstr "أنواع البرامج"
#. module: odex25_program_activity
#: model:ir.ui.menu,name:odex25_program_activity.menu_pa_activities
msgid "Activities"
msgstr "الأنشطة"
#. module: odex25_program_activity
#: model:ir.ui.menu,name:odex25_program_activity.menu_pa_medad
msgid "Medad"
msgstr "مداد"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__level_id
msgid "Program Levels"
msgstr "مستويات البرامج"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__track_id
msgid "Program Tracks"
msgstr "مسارات البرامج"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__program_id
msgid "Programs"
msgstr "البرامج"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__activity_id
msgid "Activities"
msgstr "الأنشطة"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__medad_id
msgid "Medad"
msgstr "مداد"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__rejection_reason
msgid "Rejection Reason"
msgstr "سبب الارجاع"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_activity_registration__state__draft
msgid "Draft"
msgstr "مسودة"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_activity_registration__state__social_specialist
msgid "Social Specialist"
msgstr "أخصائي اجتماعي"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_activity_registration__state__operation_manager
msgid "Operations Manager"
msgstr "رئيس العمليات"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_activity_registration__state__branch_manager
msgid "Branch Manager"
msgstr "مدير الفرع"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_activity_registration__state__activity_head
msgid "Activity Head"
msgstr "رئيس الأنشطة"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_activity_registration__state__finance_manager
msgid "Finance Management"
msgstr "إدارة المالية"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_activity_registration__state__approved
msgid "Approved"
msgstr "معتمد"
#. module: odex25_program_activity
#: model:ir.model.fields.selection,name:odex25_program_activity.selection__pa_program_activity_registration__state__refused
msgid "Refused"
msgstr "مرفوض"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__return_reason
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_return_reason_wizard__reason
msgid "Return Reason"
msgstr "سبب الإرجاع"
#. module: odex25_program_activity
#: model:ir.model.fields,field_description:odex25_program_activity.field_pa_program_activity_registration__want_transport
msgid "Does the beneficiary want transportation"
msgstr "هل يحتاج الي مواصلات"
#. module: odex25_program_activity
#: model:res.groups,name:odex25_program_activity.group_activity_social_specialist
msgid "Activity Manager"
msgstr "مدير الانشطة والتدريبات"

View File

@ -0,0 +1 @@
from . import program

View File

@ -0,0 +1,535 @@
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
from odoo.exceptions import UserError, ValidationError
class PaProgramLevel(models.Model):
_name = 'pa.program.level'
_description = 'Program Levels Screen'
_rec_name = 'name'
_order = 'code'
code = fields.Char(
string='Level Code',
required=True,
copy=False,
readonly=True,
index=True,
default=lambda self: self.env['ir.sequence'].next_by_code('pa.program.level') or _('New'),
)
name = fields.Char(
string='Level Name',
required=True,
default=lambda self: _('Technical Tracks'),
help='Enter the level name such as: cultural, cognitive, religious, developmental, preventive, therapeutic',
)
type = fields.Selection([
('route', 'Tracks'),
('activity', 'Activities'),
('medad', 'Medad'),
], string='Level Type', required=True, help='Select the type of level')
description = fields.Text(string='Level Description')
active = fields.Boolean(string='Level Status', default=True)
track_ids = fields.One2many(
'pa.program.track',
'level_id',
string='Associated Tracks',
help='Tracks that belong to this level',
)
# Optional: enforce unique code at Python level
@api.model
def create(self, vals):
if 'code' in vals:
existing = self.search([('code', '=', vals['code'])])
if existing:
raise ValidationError(_('كود المستوى يجب أن يكون فريدًا'))
return super(PaProgramLevel, self).create(vals)
class PaProgramTrack(models.Model):
_name = 'pa.program.track'
_description = 'Program Track Screen'
_rec_name = 'name'
_order = 'code'
code = fields.Char(
string='Track Code',
required=True,
copy=False,
readonly=True,
index=True,
default=lambda self: self.env['ir.sequence'].next_by_code('pa.program.track') or _('New'),
)
name = fields.Char(string='Track Name', required=True)
description = fields.Text(string='Track Description')
# branch = fields.Many2one('age.category',string='Branch')
branch = fields.Many2one("branch.settings", string='Branch', domain="[('branch_type','=','branches')]")
gender = fields.Selection(
[('male', 'Male'), ('female', 'Female')],
string='Gender',
)
age_category = fields.Many2one(
'age.category',
string='Age Category',
help='Filter track based on age category',
)
study_category = fields.Many2one('education.level',string='Study Category')
hobby = fields.Char(string='Hobby')
study_status = fields.Char(string='Study Status')
health_status = fields.Char(string='Health Status')
education_status = fields.Char(string='Educational Status')
partner_id = fields.Many2one(
'res.partner',
string='Associated Partner',
help='The partner linked to the track'
)
active = fields.Boolean(string='Track Status', default=True)
level_id = fields.Many2one(
'pa.program.level',
string='Associated Level',
required=True,
ondelete='cascade'
)
class PaProgram(models.Model):
_name = 'pa.program'
_description = 'Programs Screen'
_rec_name = 'name'
_order = 'code'
code = fields.Char(
string='Program Code',
required=True,
copy=False,
readonly=True,
index=True,
default=lambda self: self.env['ir.sequence'].next_by_code('pa.program') or _('New'),
)
name = fields.Char(string='Program Name', required=True)
program_type_id = fields.Many2one(
'pa.program.type',
string='Program Type',
)
payment_type = fields.Selection([
('paid', 'Paid'),
('unpaid', 'Unpaid')
], string='Payment Type', required=True)
sponsor_id = fields.Many2one('takaful.sponsorship', string='Linked Sponsor',
help='Sponsor is shown only if the payment type is Paid'
)
sponsor_support_amount = fields.Float(
string='Allocated Support Amount',
related='sponsor_id.total_sponsorship_amount',
readonly=True,
help='Support amount as per sponsor details'
)
budget = fields.Float(
string='Program Budget',
help='Used when payment type = Unpaid'
)
location = fields.Selection([
('inside', 'Internal'),
('outside', 'External')
], string='Program Location', required=True)
description = fields.Text(string='Program Description')
track_id = fields.Many2one(
'pa.program.track',
string='Associated Track',
help='Each program is linked to one track that contains several activities'
)
analytic_account_id = fields.Many2one(
'account.analytic.account',
string='Linked Analytic Account',
readonly=True,
help='Automatically created analytic account with the same name as the program and cannot be deleted'
)
estimated_budget = fields.Float(
string='Associated Estimated Budget',
help='Estimated budget related to the analytic account'
)
active = fields.Boolean(string='Program Status', default=True)
# @api.constrains('name')
# def _create_program_account(self):
# for rec in self:
# if not rec.name:
# continue
# # check if analytic account already exists
# analytic = self.env["account.analytic.account"].search([("name", "=", rec.name)], limit=1)
# if not analytic:
# self.env["account.analytic.account"].create({
# "name": rec.name,
# })
@api.constrains('payment_type', 'sponsor_id')
def _check_sponsor_if_paid(self):
for record in self:
if record.payment_type == 'paid' and not record.sponsor_id:
raise ValidationError(_('يجب اختيار الكافل في حالة نوع الدفع مدفوع'))
if record.payment_type == 'unpaid' and record.sponsor_id:
raise ValidationError(_('لا يجب اختيار كافل في حالة نوع الدفع غير مدفوع'))
@api.model
def create(self, vals):
res = super().create(vals) # ✅ fix
if not res.analytic_account_id:
account = self.env['account.analytic.account'].create({
'name': res.name,
'active': True,
})
res.analytic_account_id = account.id
return res
def write(self, vals):
res = super().write(vals) # ✅ same correction here
for record in self:
if not record.analytic_account_id:
account = self.env['account.analytic.account'].create({
'name': record.name,
'active': True,
})
record.analytic_account_id = account.id
return res
class PaProgramActivity(models.Model):
_name = 'pa.program.activity'
_description = 'Program Activity'
_rec_name = 'name'
code = fields.Char("Activity Code", required=True, copy=False, default=lambda self: self.env['ir.sequence'].next_by_code('pa.program.activity'))
name = fields.Char("Activity Name", required=True)
description = fields.Text("Activity Description")
program_id = fields.Many2one('pa.program', string="Related Program")
location = fields.Selection([('inside', 'Internal'), ('outside', 'External')], required=True, string="Activity Location")
date_start = fields.Datetime("Activity Start Date")
date_end = fields.Datetime("Activity End Date")
analytic_account_id = fields.Many2one('account.analytic.account', string="Analytic Account")
estimated_budget = fields.Float("Estimated Budget")
active = fields.Boolean("Active", default=True)
@api.model
def create(self, vals):
res = super().create(vals) # ✅ fix
if not res.analytic_account_id:
account = self.env['account.analytic.account'].create({
'name': res.name,
'active': True,
})
res.analytic_account_id = account.id
return res
def write(self, vals):
res = super().write(vals) # ✅ same correction here
for record in self:
if not record.analytic_account_id:
account = self.env['account.analytic.account'].create({
'name': record.name,
'active': True,
})
record.analytic_account_id = account.id
return res
class PaProgramMedad(models.Model):
_name = 'pa.program.medad'
_description = 'Medad'
_rec_name = 'name'
code = fields.Char("Medad Code", required=True, copy=False, default=lambda self: self.env['ir.sequence'].next_by_code('pa.program.medad'))
name = fields.Char("Medad Name", required=True)
description = fields.Text("Medad Description")
medad_type = fields.Selection([
('skills', 'Skills'),
('training', 'Training'),
('innovation', 'Innovation Support')
], string="Medad Type", required=True)
activity_id = fields.Many2one('pa.program.activity', string="Associated Activity")
analytic_account_id = fields.Many2one('account.analytic.account', string="Associated Analytic Account")
estimated_budget = fields.Float("Estimated Budget")
active = fields.Boolean("Active", default=True)
@api.model
def create(self, vals):
res = super().create(vals) # ✅ fix
if not res.analytic_account_id:
account = self.env['account.analytic.account'].create({
'name': res.name,
'active': True,
})
res.analytic_account_id = account.id
return res
def write(self, vals):
res = super().write(vals) # ✅ same correction here
for record in self:
if not record.analytic_account_id:
account = self.env['account.analytic.account'].create({
'name': record.name,
'active': True,
})
record.analytic_account_id = account.id
return res
# Example family/beneficiary for demo: you should replace with your actual model
class PaProgramActivityRegistration(models.Model):
_name = 'pa.program.activity.registration'
_description = 'Activity Registration'
_inherit = ['mail.thread']
name = fields.Char(string='Request Number', readonly=True, index=True,
default=lambda self: self.env['ir.sequence'].next_by_code('pa.program.activity.registration') or 'New')
request_date = fields.Datetime(string='Request Date', default=fields.Datetime.now, readonly=True)
creator_id = fields.Many2one('res.users', string='Creator', default=lambda self: self.env.user, readonly=True)
date_from = fields.Datetime(string='Date From')
date_to = fields.Datetime(string='Date To')
familye_id = fields.Many2one('grant.benefit', string='Family')
beneficiary_ids = fields.Many2many(
'family.member',
string='Beneficiary Name',
domain="[('benefit_id', '=', familye_id)]"
)
benefit_category_id = fields.Many2one(related='familye_id.benefit_category_id', string='Family Category', readonly=True)
# beneficiary_ids = fields.Many2many('family.member', string='Beneficiary Name')
sms_phone = fields.Char(related='familye_id.sms_phone', string='Mobile Number', readonly=True)
member_ids = fields.One2many(
'family.member',
'benefit_ids',
string='Family Members'
)
branch_custom_id = fields.Many2one(string='Branch', related='familye_id.branch_custom_id', readonly=True)
gender = fields.Selection(related='familye_id.gender', readonly=True)
nationality_id = fields.Many2one(string='Nationality', related='familye_id.nationality_id', readonly=True)
graduation_status = fields.Selection(string='Graduation Status', related='familye_id.graduation_status', readonly=True)
health_status = fields.Selection(string='Health Status', related='familye_id.health_status', readonly=True)
education_status = fields.Selection(string='Educational Status', related='familye_id.education_status', readonly=True)
mother_is_life = fields.Boolean(string='Is Mother Alive?', related='familye_id.mother_is_life', readonly=True)
mother_location_conf = fields.Many2one(string='Mother Location', related='familye_id.mother_location_conf', readonly=True)
is_mother_work = fields.Boolean(string='Is Mother Working?', related='familye_id.is_mother_work', readonly=True)
housing_type = fields.Selection(string='Housing Type', related='familye_id.housing_type', readonly=True)
beneficiary_relation = fields.Selection([
('mother', 'Mother'),
('son', 'Son'),
('daughter', 'Daughter')
], string='Beneficiary Relation')
sons = fields.Integer(
string="Number of Sons",
compute='_compute_sons_daughters',
store=False
)
daughters = fields.Integer(
string="Number of Daughters",
compute='_compute_sons_daughters',
store=False
)
return_reason = fields.Text(string='Return Reason')
@api.depends('familye_id', 'familye_id.member_ids', 'familye_id.member_ids.relationn',
'familye_id.member_ids.relationn.relation_type')
def _compute_sons_daughters(self):
for rec in self:
sons = 0
daughters = 0
members = rec.familye_id.member_ids.filtered(lambda m: m.relationn)
for member in members:
if member.relationn.relation_type == 'son':
sons += 1
elif member.relationn.relation_type == 'daughter':
daughters += 1
rec.sons = sons
rec.daughters = daughters
level_id = fields.Many2one('pa.program.level', string='Program Levels', required=True)
track_id = fields.Many2one('pa.program.track', string='Program Tracks')
program_id = fields.Many2one('pa.program', string='Programs')
activity_id = fields.Many2one('pa.program.activity', string='Activities')
medad_id = fields.Many2one('pa.program.medad', string='Medad')
want_transport = fields.Selection([('yes', 'Yes'), ('no', 'No')], string='Does the beneficiary want transportation')
state = fields.Selection([
('draft', 'Draft'),
('social_specialist', 'Social Specialist'),
('operation_manager', 'Operations Manager'),
('branch_manager', 'Branch Manager'),
('activity_head', 'Activity Head'),
('finance_manager', 'Finance Management'),
('approved', 'Approved'),
('refused', 'Refused')
], default='draft', tracking=True)
rejection_reason = fields.Text(string='Rejection Reason')
# To hold the last rejection note
def unlink(self):
for order in self:
if order.state not in ['draft']:
raise UserError(_('You cannot delete this record State not Draft'))
return super(PaProgramActivityRegistration, self).unlink()
@api.onchange('familye_id')
def _onchange_familye_id(self):
if self.familye_id:
# Set member_ids to the current members of the selected familye_id
# This links existing family.member records (no create)
self.member_ids = [(6, 0, self.familye_id.member_ids.ids)]
else:
self.member_ids = [(5, 0, 0)] # Clear if no familye_id
# Validation of required fields based on level type
@api.constrains('level_id', 'track_id', 'program_id', 'activity_id', 'medad_id')
def _check_required_fields_based_on_level(self):
for rec in self:
if not rec.level_id:
continue
lvl_type = rec.level_id.type
if lvl_type == 'route': # مسارات
if not rec.track_id or not rec.program_id:
raise ValidationError(_('لحالة المستوى "مسارات"، الحقول "المسار" و "البرنامج" مطلوبان'))
elif lvl_type == 'activity': # أنشطة
if not rec.track_id or not rec.program_id or not rec.activity_id:
raise ValidationError(_('لحالة المستوى "أنشطة"، الحقول "المسار" و "البرنامج" و "النشاط" مطلوبة'))
elif lvl_type == 'medad': # مداد
if not rec.track_id or not rec.program_id or not rec.activity_id or not rec.medad_id:
raise ValidationError(_('لحالة المستوى "مداد"، جميع الحقول "المسار"، "البرنامج"، "النشاط"، "المداد" مطلوبة'))
def action_to_social_specialist(self):
self.ensure_one()
self.state = 'social_specialist'
def action_approve(self):
self.ensure_one()
transition_map = {
'social_specialist': 'operation_manager',
'operation_manager': 'branch_manager',
'branch_manager': 'activity_head',
'activity_head': 'finance_manager',
'finance_manager': 'approved',
}
next_state = transition_map.get(self.state)
if next_state:
self.state = next_state
def action_refuse(self):
self.ensure_one()
self.state = 'refused'
def action_reset_to_draft(self):
self.ensure_one()
self.state = 'draft'
def action_return_to_specialist(self):
self.ensure_one()
self.state = 'social_specialist'
def action_return_to_draft(self):
# Open wizard to collect return reason - opens form view on 'empowerment.return.reason.wizard'
return {
'type': 'ir.actions.act_window',
'name': _('سبب الإرجاع'),
'view_mode': 'form',
'res_model': 'pa.return.reason.wizard',
'target': 'new',
'context': {'default_registration_id': self.id}
}
class PaReturnReasonWizard(models.TransientModel):
_name = 'pa.return.reason.wizard'
_description = 'Return Reason Wizard'
reason = fields.Text(string='Return Reason', required=True)
registration_id = fields.Many2one('pa.program.activity.registration', string='Registration Request')
def action_confirm_return(self):
if self.registration_id:
self.registration_id.rejection_reason = self.reason
# move back to draft or social_specialist depending on the context/state
if self.registration_id.state == 'operation_manager':
self.registration_id.state = 'social_specialist'
self.registration_id.return_reason = self.reason
else:
self.registration_id.state = 'draft'
self.registration_id.return_reason = self.reason
return {'type': 'ir.actions.act_window_close'}
class PaProgram(models.Model):
_name = 'pa.family'
class PaProgramType(models.Model):
_name = 'pa.program.type'
pg_type =fields.Char(string='Name')
class FamilyMember(models.Model):
_inherit = 'family.member'
benefit_ids = fields.Many2one(
'pa.program.activity.registration',
string='Benefit Registration',
ondelete='cascade',
index=True,
)
need_trans = fields.Boolean(string='Need Transportation')
need_medicin = fields.Boolean(string='Need Medicien')
need_mental_dis = fields.Boolean(string='Have Mental Disorders')

View File

@ -0,0 +1,10 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
pa_program_level_all,pa.program.level,model_pa_program_level,,1,1,1,1
pa_program_track_all,pa.program.track,model_pa_program_track,,1,1,1,1
pa_program_all,pa.program,model_pa_program,,1,1,1,1
pa_program_activity_all,pa.program.activity,model_pa_program_activity,,1,1,1,1
pa_program_medad_all,pa.program.medad,model_pa_program_medad,,1,1,1,1
pa_program_registration_all,pa.program.registration,model_pa_program_activity_registration,,1,1,1,1
pa_family_all,pa.family,model_pa_family,,1,1,1,1
pa_pa_program_type,pa.program.type,model_pa_program_type,,1,1,1,1
pa_return_reason_wizard,pa.return.reason.wizard,model_pa_return_reason_wizard,,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 pa_program_level_all pa.program.level model_pa_program_level 1 1 1 1
3 pa_program_track_all pa.program.track model_pa_program_track 1 1 1 1
4 pa_program_all pa.program model_pa_program 1 1 1 1
5 pa_program_activity_all pa.program.activity model_pa_program_activity 1 1 1 1
6 pa_program_medad_all pa.program.medad model_pa_program_medad 1 1 1 1
7 pa_program_registration_all pa.program.registration model_pa_program_activity_registration 1 1 1 1
8 pa_family_all pa.family model_pa_family 1 1 1 1
9 pa_pa_program_type pa.program.type model_pa_program_type 1 1 1 1
10 pa_return_reason_wizard pa.return.reason.wizard model_pa_return_reason_wizard 1 1 1 1

View File

@ -0,0 +1,13 @@
<odoo>
<record id="group_activity_social_specialist" model="res.groups">
<field name="name">Activity Manager</field>
<field name="category_id" ref="odex_benefit.module_category_benefit"/>
</record>
<record id="group_pa_activity_head" model="res.groups">
<field name="name">رئيس الأنشطة</field>
<field name="category_id" ref="odex_benefit.module_category_benefit"/>
</record>
</odoo>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -0,0 +1,3 @@
<odoo>
</odoo>

View File

@ -0,0 +1,680 @@
<odoo>
<record id="action_open_return_reason_wizard" model="ir.actions.act_window">
<field name="name">سبب الإرجاع</field>
<field name="res_model">pa.return.reason.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<!-- Levels Views -->
<record id="view_pa_program_level_tree" model="ir.ui.view">
<field name="name">pa.program.level.tree</field>
<field name="model">pa.program.level</field>
<field name="arch" type="xml">
<tree>
<field name="code"/>
<field name="name"/>
<field name="type"/>
<field name="active"/>
<field name="track_ids" string="المسارات المرتبطة" widget="many2many_tags"/>
</tree>
</field>
</record>
<record id="view_pa_program_level_form" model="ir.ui.view">
<field name="name">pa.program.level.form</field>
<field name="model">pa.program.level</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="code" readonly="1"/>
<field name="name" required="1" placeholder="مسارات تقنية - ثقافية معرفية دينية"/>
<field name="type" widget="selection" required="1"/>
<field name="description"/>
<field name="active"/>
</group>
<notebook>
<page string="المسارات المرتبطة">
<field name="track_ids" context="{'default_level_id': active_id}">
<tree editable="bottom">
<field name="code"/>
<field name="name"/>
<field name="branch"/>
<field name="gender"/>
<field name="age_category"/>
<field name="study_category"/>
<field name="hobby"/>
<field name="study_status"/>
<field name="health_status"/>
<field name="education_status"/>
<field name="partner_id"/>
<field name="active"/>
</tree>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="view_pa_program_level_search" model="ir.ui.view">
<field name="name">pa.program.level.search</field>
<field name="model">pa.program.level</field>
<field name="arch" type="xml">
<search>
<field name="code"/>
<field name="name"/>
<filter name="active_filter" string="نشط" domain="[('active', '=', True)]"/>
</search>
</field>
</record>
<record id="action_pa_program_level" model="ir.actions.act_window">
<field name="name">مستويات البرامج</field>
<field name="res_model">pa.program.level</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_pa_program_level_search"/>
</record>
<!-- Tracks Views -->
<record id="view_pa_program_track_tree" model="ir.ui.view">
<field name="name">pa.program.track.tree</field>
<field name="model">pa.program.track</field>
<field name="arch" type="xml">
<tree>
<field name="code"/>
<field name="name"/>
<field name="branch"/>
<field name="gender"/>
<field name="age_category"/>
<field name="study_category"/>
<field name="hobby"/>
<field name="study_status"/>
<field name="health_status"/>
<field name="education_status"/>
<field name="partner_id"/>
<field name="active"/>
<field name="level_id"/>
</tree>
</field>
</record>
<record id="view_pa_program_track_form" model="ir.ui.view">
<field name="name">pa.program.track.form</field>
<field name="model">pa.program.track</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="code" readonly="1"/>
<field name="name" required="1"/>
<field name="description"/>
</group>
<group>
<field name="branch"/>
<field name="gender" widget="selection"/>
<field name="age_category" />
<field name="study_category"/>
<field name="hobby"/>
<field name="study_status"/>
<field name="health_status"/>
<field name="education_status"/>
<field name="partner_id"/>
<field name="active"/>
<field name="level_id" required="1"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_pa_program_track_search" model="ir.ui.view">
<field name="name">pa.program.track.search</field>
<field name="model">pa.program.track</field>
<field name="arch" type="xml">
<search>
<field name="code"/>
<field name="name"/>
<field name="level_id" string="المستوى المرتبط"/>
<filter name="active_filter" string="نشط" domain="[('active', '=', True)]"/>
</search>
</field>
</record>
<record id="action_pa_program_track" model="ir.actions.act_window">
<field name="name">مسارات البرامج</field>
<field name="res_model">pa.program.track</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_pa_program_track_search"/>
</record>
<!-- Programs Views -->
<record id="view_pa_program_tree" model="ir.ui.view">
<field name="name">pa.program.tree</field>
<field name="model">pa.program</field>
<field name="arch" type="xml">
<tree>
<field name="code"/>
<field name="name"/>
<field name="program_type_id" />
<!-- <field name="kind"/>-->
<field name="payment_type"/>
<field name="sponsor_id"/>
<field name="sponsor_support_amount"/>
<field name="budget"/>
<field name="location"/>
<field name="active"/>
<field name="track_id"/>
</tree>
</field>
</record>
<record id="view_pa_program_form" model="ir.ui.view">
<field name="name">pa.program.form</field>
<field name="model">pa.program</field>
<field name="arch" type="xml">
<form string="البرنامج">
<sheet>
<group>
<field name="code" readonly="1"/>
<field name="name" required="1"/>
<field name="program_type_id" />
<!-- <field name="kind" widget="selection" required="1"/>-->
<field name="payment_type" required="1"/>
<field name="sponsor_id" attrs="{'invisible': [('payment_type','!=','paid')]}"/>
<field name="sponsor_support_amount"/>
<field name="budget"/>
<field name="location" widget="selection" required="1"/>
<field name="description"/>
</group>
<group>
<field name="track_id" required="1"/>
<field name="analytic_account_id" options="{'no_create': True}" readonly="1"/>
<!-- <field name="estimated_budget"/>-->
<field name="active"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_pa_program" model="ir.actions.act_window">
<field name="name">البرامج</field>
<field name="res_model">pa.program</field>
<field name="view_mode">tree,form</field>
</record>
<!-- Activities Views -->
<record id="view_pa_program_activity_tree" model="ir.ui.view">
<field name="name">pa.program.activity.tree</field>
<field name="model">pa.program.activity</field>
<field name="arch" type="xml">
<tree>
<field name="code"/>
<field name="name"/>
<field name="program_id"/>
<field name="location"/>
<field name="date_start"/>
<field name="date_end"/>
<field name="active"/>
</tree>
</field>
</record>
<record id="view_pa_program_activity_form" model="ir.ui.view">
<field name="name">pa.program.activity.form</field>
<field name="model">pa.program.activity</field>
<field name="arch" type="xml">
<form string="النشاط">
<sheet>
<group>
<field name="code" readonly="1"/>
<field name="name" required="1"/>
<field name="description"/>
</group>
<group>
<field name="program_id" required="1"/>
<field name="location" widget="selection" required="1"/>
<field name="date_start"/>
<field name="date_end"/>
<field name="analytic_account_id" options="{'no_create': True}" readonly="1"/>
<!-- <field name="estimated_budget"/>-->
<field name="active"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_pa_program_activity" model="ir.actions.act_window">
<field name="name">الأنشطة</field>
<field name="res_model">pa.program.activity</field>
<field name="view_mode">tree,form</field>
</record>
<!-- Medad Views -->
<record id="view_pa_program_medad_tree" model="ir.ui.view">
<field name="name">pa.program.medad.tree</field>
<field name="model">pa.program.medad</field>
<field name="arch" type="xml">
<tree>
<field name="code"/>
<field name="name"/>
<field name="medad_type"/>
<field name="activity_id"/>
<field name="active"/>
</tree>
</field>
</record>
<record id="view_pa_program_medad_form" model="ir.ui.view">
<field name="name">pa.program.medad.form</field>
<field name="model">pa.program.medad</field>
<field name="arch" type="xml">
<form string="مداد">
<sheet>
<group>
<field name="code" readonly="1"/>
<field name="name" required="1"/>
<field name="description"/>
</group>
<group>
<field name="medad_type" widget="selection" required="1"/>
<field name="activity_id" required="0"/>
<field name="analytic_account_id" options="{'no_create': True}" readonly="1"/>
<!-- <field name="estimated_budget"/>-->
<field name="active"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_pa_program_medad" model="ir.actions.act_window">
<field name="name">مداد</field>
<field name="res_model">pa.program.medad</field>
<field name="view_mode">tree,form</field>
</record>
<record id="view_pa_program_activity_registration_form" model="ir.ui.view">
<field name="name">pa.program.activity.registration.form</field>
<field name="model">pa.program.activity.registration</field>
<field name="arch" type="xml">
<form string="تسجيل الأنشطة">
<sheet>
<header>
<field name="state" widget="statusbar"
statusbar_visible="draft,social_specialist,operation_manager,branch_manager,activity_head,finance_manager,approved,refused"/>
<button name="action_to_social_specialist"
string="اعتماد الاخصائي الاجتماعي" type="object"
class="oe_highlight" states="draft"
groups="odex_benefit.group_pa_social_specialist"/>
<button name="action_approve" string="اعتماد" type="object"
states="social_specialist,operation_manager,branch_manager,activity_head,finance_manager"
groups="odex_benefit.group_pa_operation_manager,odex_benefit.group_pa_branch_manager,odex25_program_activity.group_pa_activity_head,odex_benefit.group_pa_finance_manager"/>
<button name="action_refuse" string="رفض" type="object"
states="draft,social_specialist,operation_manager,branch_manager,activity_head,finance_manager"
groups="odex25_program_activity.group_social_specialist,odex_benefit.group_pa_operation_manager,odex_benefit.group_pa_branch_manager,odex25_program_activity.group_pa_activity_head,odex_benefit.group_pa_finance_manager"/>
<button type="object" name="action_return_to_draft"
string="إعادة إلى المسودة"
groups="odex25_program_activity.group_social_specialist,odex_benefit.group_pa_operation_manager"
states="social_specialist,operation_manager"/>
<button type="object" name="action_return_to_draft"
string="إعادة إلى الأخصائي الاجتماعي"
groups="odex_benefit.group_pa_operation_manager" states="operation_manager"/>
</header>
<group string="معلومات الإنشاء" col="2">
<field name="name" readonly="1"/>
<field name="request_date" readonly="1"/>
<field name="creator_id" readonly="1"/>
<field name="date_from"/>
<field name="date_to"/>
</group>
<group string="معلومات الأسرة" col="2">
<!-- domain="[('mother_marital_status','=','widow')]"-->
<!-- <field name="family_id" />-->
<field name="familye_id" />
<field name="branch_custom_id" />
<field name="benefit_category_id" />
<field name="gender" />
<field name="nationality_id" />
<field name="graduation_status" />
<field name="health_status" />
<field name="education_status" />
<!-- <field name="familye_member"/>-->
<field name="beneficiary_relation"/>
<!-- <field name="beneficiary_ids"/>-->
<field name="sms_phone" readonly="1"/>
</group>
<group string="معلومات البرامج والأنشطة" col="2">
<field name="level_id" required="1"/>
<field name="track_id"/>
<field name="program_id"/>
<field name="activity_id"/>
<field name="medad_id"/>
<field name="want_transport"/>
<field name="return_reason"/>
</group>
<notebook string="بيانات احصائية">
<page string="بيانات الأبناء">
<group>
<field name="sons" readonly="1"/>
<field name="daughters" readonly="1"/>
</group>
</page>
<page string="بيانات الأم">
<group>
<field name="mother_is_life" readonly="1"/>
<field name="mother_location_conf" readonly="1"/>
<field name="is_mother_work" readonly="1"/>
<field name="education_status" readonly="1"/>
<!-- <field name="mother_education" readonly="1"/>-->
<field name="housing_type" readonly="1"/>
</group>
</page>
<page string="بيانات المستفيد">
<field name="member_ids" widget="one2many_list"
readonly="1" edit="0" create="0">
<form string="Family Member">
<widget name="web_ribbon" title="Non Benefit Member" bg_color="bg-danger"
attrs="{'invisible': [('member_status', '!=', 'non_benefit')]}"/>
<widget name="web_ribbon" title="Benefit Member" bg_color="bg-success"
attrs="{'invisible': [('member_status', '!=', 'benefit')]}"/>
<sheet>
<group>
<label for="relationn" string="Relation"/>
<div>
<field name="relationn" class="oe_inline" nolabel="1"
attrs="{'readonly':[('parent.state','not in',['draft','new','complete_info'])]}"
options='{"no_open": True,"no_create_edit": True}'
required="1"/>
<field name="relation" class="oe_inline" nolabel="1" invisible="1"/>
</div>
</group>
<group>
<group>
<field placeholder="Name" name="name" class="oe_inline" readonly="1"
force_save="1" invisible="1"/>
<field name="is_mother" invisible="1"/>
<field name="member_first_name" force_save="1"
attrs="{'invisible':[('is_mother','=',True)],'required':[('is_mother','=',False)]}"/>
<field name="mother_first_name" force_save="1"
attrs="{'invisible':[('is_mother','=',False)],'required':[('is_mother','=',True)]}"/>
<field name="member_third_name" force_save="1"
attrs="{'invisible':[('is_mother','=',True)],'required':[('is_mother','=',False)]}"/>
<field name="mother_third_name" force_save="1"
attrs="{'invisible':[('is_mother','=',False)],'required':[('is_mother','=',True)]}"/>
<field name="member_id_number" required="1"/>
<field name="is_dead"/>
<field name="death_certificate" widget="many2many_attachment_preview"
attrs="{'invisible':[('is_dead','=',False)]}"/>
<!-- <field name="gender" required="1"/>-->
<field name="member_location" force_save="1" invisible="1"/>
<field name="relationn_type" invisible="1"/>
<field name="member_location_conf" required="1" domain="[('location_type', '=', relationn_type in ['mother','replacement_mother'] and 'mother_location' or 'member')]"
options="{'no_create': True, 'no_create_edit': True}"/>
<field name="is_work" attrs="{'invisible':[('age','&lt;',18)]}"/>
<field name="member_income"
attrs="{'invisible':['|',('age','&lt;',18),('is_work','=',False)], 'required':[('is_work','=',True)]}"/>
<field name="salary_certificate" widget="many2many_attachment_preview" attrs="{'invisible':['|',('age','&lt;',18),('is_work','=',False)]}"/>
<field name="minor_siblings" readonly="1" force_save="1"/>
<field name="sponsor_id"/>
<field name="is_excluded_suspension" invisible="1" readonly="1" force_save="1"/>
<field name="member_status" readonly="1" widget="badge"
decoration-success="member_status == 'benefit'"
decoration-danger="member_status == 'non_benefit'"/>
</group>
<group>
<field name="member_second_name" force_save="1"
attrs="{'invisible':[('is_mother','=',True)],'required':[('is_mother','=',False)]}"/>
<field name="mother_second_name" force_save="1"
attrs="{'invisible':[('is_mother','=',False)],'required':[('is_mother','=',True)]}"/>
<field name="member_family_name" force_save="1"
attrs="{'invisible':[('is_mother','=',True)],'required':[('is_mother','=',False)]}"/>
<field name="mother_family_name" force_save="1"
attrs="{'invisible':[('is_mother','=',False)],'required':[('is_mother','=',True)]}"/>
<field name="benefit_ids" invisible="1"/>
<field name="member_phone"
attrs="{'invisible':[('is_mother','=',True)]}"/>
<field name="birth_date" required="1"/>
<field name="age" required="1"/>
<field name="age_status"/>
<field name="is_married"
attrs="{'invisible':[('is_mother','=',True)]}"/>
<field name="need_trans"/>
<field name="need_medicin"/>
<field name="need_mental_dis"/>
<field name="marriage_certificate"
widget="many2many_attachment_preview"
attrs="{'invisible':['|',('is_mother','=',True),('is_married','=',False)]}"/>
<field name="mother_marital_conf"
attrs="{'invisible':[('is_mother','=',False)]}"
options="{'no_create': True, 'no_create_edit': True}"
groups="!odex_benefit.group_benefit_manager"/>
<field name="mother_location" invisible="1"/>
</group>
</group>
<notebook>
<page string="الهوايات">
<field name="hobbies_attachment_ids" widget="one2many_list">
<tree editable="bottom">
<field name="hobbies_id" required="1"/>
<field name="name"/>
<field name="datas" widget="binary"
filename="attachment_file_name"/>
<button name="action_preview_attachment" type="object"
string="Preview Attachment"/>
<field name="expiration_date"/>
<field name="attach_status"/>
<field name="member_id" invisible="1"/>
</tree>
</field>
</page>
<page string="الامراض">
<field name="diseases_attachment_ids" widget="one2many_list">
<tree editable="bottom">
<field name="diseases_id" required="1"/>
<field name="name"/>
<field name="datas" widget="binary"
filename="attachment_file_name"/>
<button name="action_preview_attachment" type="object"
string="Preview Attachment"/>
<field name="expiration_date"/>
<field name="attach_status"/>
<field name="member_id" invisible="1"/>
</tree>
</field>
</page>
<page string="الاعاقات">
<field name="disabilities_attachment_ids" widget="one2many_list">
<tree editable="bottom">
<field name="disabilities_id" required="1"/>
<field name="name"/>
<field name="datas" widget="binary"
filename="attachment_file_name"/>
<button name="action_preview_attachment" type="object"
string="Preview Attachment"/>
<field name="expiration_date"/>
<field name="attach_status"/>
<field name="member_id" invisible="1"/>
</tree>
</field>
</page>
<page string="الحالة التعليمية">
<h3>Education Status</h3>
<field name="member_education_status_ids" mode="tree,form"/>
</page>
<page string="المستندات التعريفية">
<field name="attachment_ids" widget="one2many_list">
<tree editable="bottom" delete="0">
<field name="name" string="Attachment Name"
attrs="{'readonly':[('is_default','=',True)]}"
force_save="1"/>
<field name="attach_id" invisible="1"/>
<field name="datas" widget="binary"
filename="attachment_file_name"/>
<button name="action_preview_attachment" type="object"
string="Preview Attachment"/>
<field name="expiration_date"/>
<field name="attach_status"/>
<field name="allow_days"/>
<field name="benefit_id" invisible="1"/>
<field name="is_required" invisible="1"/>
<field name="is_default" invisible="1"/>
</tree>
</field>
<group>
<field name="state" invisible="1"/>
<field name="required_attach"
attrs="{'required':[('state','not in',['draft','new'])]}"/>
</group>
</page>
</notebook>
</sheet>
</form>
<tree string="Family Members" delete="0" create="0" edit="0">
<field name="name" force_save="1"/>
<!-- <field name="gender" required="1"/>-->
<field name="relationn"/>
<field name="member_location_conf"/>
<field name="member_status" string="Is Benefit?"/>
<field name="age"/>
<field name="benefit_id"/>
<field name="state"/>
</tree>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<!-- Tree View -->
<record id="view_pa_program_activity_registration_tree" model="ir.ui.view">
<field name="name">pa.program.activity.registration.tree</field>
<field name="model">pa.program.activity.registration</field>
<field name="arch" type="xml">
<tree string="طلبات تسجيل الأنشطة">
<field name="name"/>
<field name="familye_id"/>
<field name="level_id"/>
<field name="state"/>
<field name="request_date"/>
</tree>
</field>
</record>
<!-- Action -->
<record id="action_pa_program_activity_registration" model="ir.actions.act_window">
<field name="name">تسجيل الأنشطة</field>
<field name="res_model">pa.program.activity.registration</field>
<field name="view_mode">tree,form</field>
</record>
<!-- Wizard form and action -->
<record id="view_pa_return_reason_wizard_form" model="ir.ui.view">
<field name="name">pa.return.reason.wizard.form</field>
<field name="model">pa.return.reason.wizard</field>
<field name="arch" type="xml">
<form string="سبب الإرجاع" >
<group>
<field name="reason" />
</group>
<footer>
<button string="تأكيد" type="object" name="action_confirm_return" class="btn-primary"/>
<button string="إلغاء" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="pa_program_type_tree" model="ir.ui.view">
<field name="name">pa.program.type.tree</field>
<field name="model">pa.program.type</field>
<field name="arch" type="xml">
<tree>
<field name="pg_type"/>
</tree>
</field>
</record>
<record id="pa_program_type_form" model="ir.ui.view">
<field name="name">pa.program.type.form</field>
<field name="model">pa.program.type</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="pg_type" required="1" />
</group>
</sheet>
</form>
</field>
</record>
<record id="action_pa_program_type" model="ir.actions.act_window">
<field name="name">انواع البرامج</field>
<field name="res_model">pa.program.type</field>
<field name="view_mode">tree,form</field>
</record>
<!-- Root Settings Menu -->
<!-- Menu -->
<menuitem id="menu_pa_root" name="Programs and Activities" web_icon="odex25_program_activity,static/description/icon.png" sequence="1" groups="odex25_program_activity.group_activity_social_specialist"/>
<menuitem id="menu_pa_registration" parent="menu_pa_root" name="Activity Registration" sequence="20" action="action_pa_program_activity_registration"/>
<menuitem id="menu_pa_settings" name="Settings" parent="menu_pa_root" sequence="90"/>
<!-- Levels menu -->
<menuitem id="menu_pa_levels" name="Program Levels" parent="menu_pa_settings" action="action_pa_program_level"/>
<!-- Tracks menu -->
<menuitem id="menu_pa_tracks" name="Program Tracks" parent="menu_pa_settings" action="action_pa_program_track"/>
<!-- Programs menu -->
<menuitem id="menu_pa_programs" name="Programs" parent="menu_pa_settings" action="action_pa_program"/>
<menuitem id="menu_pa_program_type" name="Program Types" parent="menu_pa_settings" action="action_pa_program_type"/>
<!-- Activities menu -->
<menuitem id="menu_pa_activities" name="Activities" parent="menu_pa_settings" action="action_pa_program_activity"/>
<!-- Medad menu -->
<menuitem id="menu_pa_medad" name="Medad" parent="menu_pa_settings" action="action_pa_program_medad"/>
</odoo>

View File

@ -0,0 +1,634 @@
# 📋 مراجعة شاملة لموديول Odex Benefit
## 🎯 نظرة عامة
**اسم الموديول:** `odex_benefit`
**الإصدار:** 1.0
**الفئة:** Grant Management
**الشركة المطورة:** Expert Ltd
**الموقع:** http://exp-sa.com
**الترخيص:** GPL-3
### الوصف
موديول شامل لإدارة المنح والمساعدات لمشروع التكافل، يوفر نظام متكامل لإدارة الأسر المستفيدة، أعضاء الأسرة، الخدمات المقدمة، الزيارات، والمصروفات.
---
## 📦 الاعتمادات (Dependencies)
الموديول يعتمد على:
- `base` - الأساسيات
- `survey` - الاستبيانات
- `takaful_core` - نواة التكافل
- `website` - الموقع الإلكتروني
- `account` - المحاسبة
- `report_xlsx` - التقارير
- `sale` - المبيعات
- `product` - المنتجات
- `stock` - المخزون
- `hr` - الموارد البشرية
- `purchase` - المشتريات
- `web_google_maps` - خرائط جوجل
- `odex25_account_payment_fix` - إصلاحات الدفع
- `otp_sms_auth_custom` - المصادقة عبر OTP
### المكتبات الخارجية
- `num2words` - تحويل الأرقام إلى كلمات
---
## 🏗️ البنية الهيكلية للموديول
### 1. النماذج الرئيسية (Models)
#### 1.1 `grant.benefit` - الملف الرئيسي للأسرة المستفيدة
**الوصف:** النموذج الأساسي الذي يمثل الأسرة المستفيدة من المنح
**الحقول الرئيسية:**
- **المعلومات الأساسية:**
- `code`: رقم الملف (تسلسلي)
- `name`: اسم الأسرة
- `partner_id`: ربط مع شريك (res.partner)
- `benefit_type`: نوع الاستفادة (benefit/orphan/widow)
- `benefit_category_id`: فئة الاستفادة
- `state`: حالة الملف (draft/new/complete_info/waiting_approve/first_approve/second_approve/refused/suspended_second_approve/exception_second_approve/black_list)
- **معلومات الأب:**
- `father_id_number`: رقم هوية الأب
- `father_birth_date`: تاريخ ميلاد الأب
- `father_age`: عمر الأب (محسوب)
- `father_marital`: الحالة الاجتماعية للأب
- `father_job_id`: الوظيفة
- `father_dead_date`: تاريخ الوفاة
- `father_dead_reason_id`: سبب الوفاة
- **معلومات الأم:**
- `mother_name`: اسم الأم
- `mother_id_number`: رقم هوية الأم
- `mother_birth_date`: تاريخ ميلاد الأم
- `mother_age`: عمر الأم (محسوب)
- `mother_marital_conf`: الحالة الاجتماعية للأم
- `mother_income`: دخل الأم
- `is_mother_work`: هل تعمل الأم؟
- `mother_has_disabilities`: هل لديها إعاقة؟
- `add_replacement_mother`: إضافة أم بديلة
- **معلومات السكن:**
- `housing_type`: نوع السكن (apartment/villa/popular_house/tent)
- `property_type`: نوع الملكية (ownership/rent/charitable/ownership_shared/rent_shared)
- `rent_amount`: مبلغ الإيجار
- `contract_num`: رقم عقد الإيجار
- `rent_start_date`: تاريخ بداية الإيجار
- `rent_end_date`: تاريخ نهاية الإيجار
- `payment_type`: نوع الدفع (Yearly/Half-yearly/Quarterly/Monthly)
- `lat`, `lon`: الإحداثيات الجغرافية
- **المعلومات المالية:**
- `total_income`: إجمالي الدخل
- `total_expenses`: إجمالي المصروفات
- `benefit_needs_percent`: نسبة الحاجة
- `family_monthly_income`: الدخل الشهري للأسرة
- `family_monthly_meals`: الوجبات الشهرية
- `family_monthly_clotting`: الملابس الشهرية
- **معلومات الأعضاء:**
- `member_ids`: قائمة أعضاء الأسرة (One2many)
- `benefit_member_count`: عدد الأعضاء المستفيدين (محسوب)
- `non_member_count`: عدد غير المستفيدين
- **معلومات الفرع:**
- `branch_custom_id`: الفرع
- `district_id`: الحي
- `meal_card`: بطاقة الوجبات
- `researcher_id`: الباحث المسؤول
- **الحالات الخاصة:**
- `is_excluded_suspension`: مستثنى من الإيقاف
- `suspend_reason`: سبب الإيقاف
- `exception_reason`: سبب الاستثناء
- `exception_type`: نوع الاستثناء (temporarily/permanent)
**الوظائف الرئيسية:**
- `check_mother_status()`: التحقق من حالة الأم
- `check_replacement_mother_status()`: التحقق من حالة الأم البديلة
- `get_members_count()`: حساب عدد الأعضاء
- `get_total_income()`: حساب إجمالي الدخل
- `get_total_expenses()`: حساب إجمالي المصروفات
- `create_scheduled_visit()`: إنشاء زيارات مجدولة تلقائياً
- `send_expiry_date_notification()`: إرسال إشعارات انتهاء المرفقات
- `update_data_automatically()`: تحديث البيانات تلقائياً
- `action_auto_exception()`: التحقق من الاستثناءات المؤقتة
#### 1.2 `family.member` - أعضاء الأسرة
**الوصف:** يمثل كل فرد من أفراد الأسرة
**الحقول الرئيسية:**
- **المعلومات الشخصية:**
- `member_first_name`: الاسم الأول
- `member_second_name`: الاسم الثاني (مرتبط بالأب)
- `member_third_name`: الاسم الثالث
- `member_family_name`: اسم العائلة
- `member_id_number`: رقم الهوية
- `gender`: الجنس (male/female)
- `birth_date`: تاريخ الميلاد
- `age`: العمر (محسوب)
- `age_status`: حالة العمر (minor/non_minor)
- `relationn`: صلة القرابة (son/daughter/mother/replacement_mother)
- **معلومات الأم (إذا كانت العضو):**
- `mother_first_name`: الاسم الأول للأم
- `mother_marital_conf`: الحالة الاجتماعية
- `mother_location`: موقع الأم
- `is_mother_work`: هل تعمل؟
- **معلومات العمل:**
- `is_work`: هل يعمل؟
- `member_income`: الدخل
- `salary_certificate`: شهادة الراتب
- **معلومات التعليم:**
- `education_status`: حالة التعليم (educated/illiterate/under_study_age)
- `case_study`: حالة الدراسة (continuous/intermittent/graduate)
- `education_levels`: المستوى التعليمي
- `specialization_ids`: التخصص
- `is_scientific_specialty`: تخصص علمي؟
- `is_medical_specialty`: تخصص طبي؟
- `member_education_status_ids`: سجل الحالة التعليمية
- **معلومات الصحة:**
- `diseases_ids`: الأمراض
- `disabilities_ids`: الإعاقات
- `hobbies_ids`: الهوايات
- **الحالة:**
- `state`: حالة العضو (draft/new/complete_info/waiting_approve/first_approve/second_approve/refused/suspended_second_approve/exception_second_approve/black_list)
- `member_status`: حالة الاستفادة (benefit/non_benefit)
- `non_benefit_reason`: سبب عدم الاستفادة
- `is_excluded_suspension`: مستثنى من الإيقاف
**الوظائف الرئيسية:**
- `check_member_status()`: التحقق من حالة الاستفادة للعضو
- `_compute_get_age_date()`: حساب العمر
- `_compute_get_age_status()`: حساب حالة العمر
- `_compute_minor_siblings()`: حساب وجود أشقاء قاصرين
#### 1.3 `service.request` - طلبات الخدمات
**الوصف:** يمثل طلب خدمة من الأسرة أو العضو
**الحقول الرئيسية:**
- **المعلومات الأساسية:**
- `name`: رقم الطلب (تسلسلي)
- `date`: تاريخ الطلب
- `benefit_type`: نوع الاستفادة (family/member)
- `family_id`: الأسرة
- `member_id`: العضو (إذا كان للعضو)
- `service_cat`: فئة الخدمة
- `service_type`: نوع الخدمة (rent/home_restoration/electrical_devices/marriage/etc.)
- **معلومات الخدمة:**
- `requested_service_amount`: المبلغ المطلوب
- `service_max_amount`: الحد الأقصى المسموح
- `description`: الوصف
- `need_status`: حالة الحاجة (urgent/not_urgent)
- **معلومات الإيجار (للخدمات المتعلقة بالإيجار):**
- `rent_contract_number`: رقم عقد الإيجار
- `rent_start_date`: تاريخ بداية الإيجار
- `rent_end_date`: تاريخ نهاية الإيجار
- `rent_amount`: مبلغ الإيجار
- `payment_type`: نوع الدفع
- `estimated_rent_amount`: المبلغ المقدر للإيجار
- `new_rent_contract`: عقد إيجار جديد؟
- **الحالة:**
- `state`: حالة الطلب (draft/researcher/waiting_approve/first_approve/family_services_manager/legal_department/projects_department/gm_assistant/accounting_approve/approval_of_beneficiary_services/send_request_to_supplier/family_received_device/refused)
- `payment_order_id`: أمر الدفع المرتبط
- `payment_order_state`: حالة أمر الدفع
- **المرفقات:**
- `attachment_lines`: قائمة المرفقات المطلوبة
- `service_attach`: مرفقات الخدمة
**الوظائف الرئيسية:**
- `_get_estimated_rent_amount()`: حساب المبلغ المقدر للإيجار
- `_get_aid_amount()`: حساب مبلغ المساعدة
- `_compute_attachment_lines()`: حساب المرفقات المطلوبة
- `action_create_payment_order()`: إنشاء أمر دفع
- `create_vendor_bill()`: إنشاء فاتورة مورد
#### 1.4 `visit.location` - الزيارات
**الوصف:** يمثل زيارة للأسرة
**الحقول الرئيسية:**
- **المعلومات الأساسية:**
- `name`: رقم الزيارة (تسلسلي)
- `benefit_id`: الأسرة المستفيدة
- `visit_date`: تاريخ الزيارة
- `visit_types`: نوع الزيارة
- `visit_objective`: هدف الزيارة (inform_visit/objective_visit)
- `researcher_ids`: الباحثون
- **الحالة:**
- `state`: حالة الزيارة (draft/contact/schedule_a_visit/pending/done/close/cancel)
- **المصادقة:**
- `otp_code`: رمز OTP
- `otp_generated_at`: وقت إنشاء OTP
- `response_id`: استجابة الاستبيان
**الوظائف الرئيسية:**
- `generateOTP()`: إنشاء رمز OTP
- `action_send_survey()`: إرسال استبيان التقييم
- `action_done()`: إتمام الزيارة
#### 1.5 `confirm.benefit.expense` - تأكيد مصروفات الأسرة
**الوصف:** تأكيد ودفع المصروفات الشهرية للأسرة
**الحقول الرئيسية:**
- **المعلومات الأساسية:**
- `family_expense_seq`: رقم المصروف (تسلسلي)
- `date`: التاريخ
- `start_date`: تاريخ البداية
- `end_date`: تاريخ النهاية
- `expense_type`: نوع المصروف (family_expense/family_invoice)
- `family_ids`: الأسر المختارة
- **المصروفات:**
- `cash_expense`: تضمين المصروف النقدي؟
- `meal_expense`: تضمين مصروف الوجبات؟
- `cloth_expense`: تضمين مصروف الملابس؟
- `family_monthly_income`: إجمالي الدخل الشهري
- `family_monthly_meals`: إجمالي الوجبات الشهرية
- `family_monthly_clotting`: إجمالي الملابس الشهرية
- **الحالة:**
- `state`: الحالة (draft/calculated/assistant_general_manager/depart_manager/account_manager/cancel/confirm)
**الوظائف الرئيسية:**
- `action_calculate()`: حساب المصروفات
- `action_confirm_selected()`: تأكيد المصروفات وإنشاء قيود محاسبية
- `_update_benefit_expense_lines()`: تحديث بنود المصروفات
#### 1.6 `payment.orders` - أوامر الدفع
**الوصف:** يمثل أمر دفع لخدمات متعددة
**الحقول الرئيسية:**
- **المعلومات الأساسية:**
- `name`: رقم أمر الدفع (تسلسلي)
- `payment_order_date`: تاريخ أمر الدفع
- `accountant_id`: المحاسب المسؤول
- `service_requests_ids`: طلبات الخدمات المرتبطة
- `journal_id`: دفتر اليومية
- **الحالة:**
- `state`: الحالة (draft/waiting_head/waiting_finance/waiting_gm/done/refused)
**الوظائف الرئيسية:**
- `get_lines()`: إنشاء بنود القيد المحاسبي
- `action_manager_approval()`: موافقة المدير
- `action_finance_approval()`: موافقة المالية وإنشاء القيد
#### 1.7 `services.settings` - إعدادات الخدمات
**الوصف:** إعدادات وتكوين الخدمات المتاحة
**الحقول الرئيسية:**
- **المعلومات الأساسية:**
- `service_name`: اسم الخدمة
- `service_type`: نوع الخدمة (rent/home_restoration/electrical_devices/etc.)
- `benefit_type`: نوع الاستفادة (family/member)
- `service_category`: فئة الخدمة (emergency/permanent/exceptional/seasonal)
- `is_seasonal_service`: خدمة موسمية؟
- **الحدود والقيود:**
- `max_amount`: الحد الأقصى للمبلغ
- `max_age`: الحد الأقصى للعمر
- `allowed_recurrence`: السماح بالتكرار (once/periodic/unlimited)
- `recurrence_period`: فترة التكرار (months/years)
- `recurrence_interval`: فترة التكرار
- `max_limit_type`: نوع الحد الأقصى (none/fixed/category/amount_person/etc.)
- `max_limit_period`: فترة الحد الأقصى (request/individual/month/year/recurrence_period)
- **الموافقات:**
- `needs_beneficiary_manager_approval`: يحتاج موافقة مدير المستفيدين؟
- `needs_services_head_approval`: يحتاج موافقة رئيس الخدمات؟
- `needs_legal_approval`: يحتاج موافقة قانونية؟
- `needs_project_management_approval`: يحتاج موافقة إدارة المشاريع؟
- **البيانات المرتبطة:**
- `rent_lines`: بنود الإيجار (حسب الفئة وعدد الأعضاء)
- `electrical_devices_lines`: بنود الأجهزة الكهربائية
- `home_furnishing_lines`: بنود تأثيث المنزل
- `category_amount_lines`: بنود المبالغ حسب الفئة
- `bill_lines`: بنود الفواتير
- `limit_person_line_ids`: حدود حسب عدد الأشخاص
#### 1.8 نماذج أخرى مهمة
**`benefit.category`** - فئات الاستفادة
- `name`: اسم الفئة
- `gender`: الجنس (male/female/both)
- `age_from`, `age_to`: نطاق العمر
- `mini_income_amount`, `max_income_amount`: نطاق الدخل
**`family.expense`** - مصروفات الأسرة
- `name`: اسم المصروف
- `expenses_type`: نوع المصروف (governmental/medical/transportation/etc.)
- `amount`: المبلغ
- `state`: الحالة (waiting/accepted/refused)
**`family.expense.line`** - بنود مصروفات الأسرة
- `expenses_type_custom`: نوع المصروف
- `amount`: المبلغ
- `state`: الحالة
- `deduct_from_family_income`: خصم من دخل الأسرة؟
**`visit.survey`** - استبيانات الزيارات
- ربط الزيارات مع استبيانات التقييم
**`seasonal.service`** - الخدمات الموسمية
- خدمات موسمية مثل رمضان، العيد، الشتاء
**`payment`** - المدفوعات
- إدارة المدفوعات للخدمات
---
## 🔐 الأمان والصلاحيات
### مجموعات المستخدمين:
1. **`group_benefit_researcher`** - الباحثون
2. **`group_benefit_woman_commitee`** - لجنة النساء
3. **`group_benefit_branch_manager`** - مديرو الفروع
4. **`group_benefit_manager`** - المديرون
5. **`group_benefit_edit`** - المحررون
6. **`group_benefit_info`** - المعلومات
7. **`group_benefit_payment_accountant_accept`** - المحاسبون
### ملفات الأمان:
- `security/security_view.xml`: تعريف مجموعات المستخدمين
- `security/ir.model.access.csv`: صلاحيات الوصول للنماذج
---
## ⚙️ الإعدادات والتكوين
### 1. `family.validation.setting` - إعدادات التحقق من الأسرة
- `female_benefit_age`: سن الاستفادة للإناث
- `male_benefit_age`: سن الاستفادة للذكور
- `exceptional_age_scientific_specialty`: سن استثنائي للتخصص العلمي
- `exceptional_age_medical_specialty`: سن استثنائي للتخصص الطبي
- `exceptional_age_has_disabilities`: سن استثنائي للإعاقة
- `minor_siblings_age`: سن الأشقاء القاصرين
- `max_income_for_benefit`: الحد الأقصى للدخل للاستفادة
### 2. `branch.settings` - إعدادات الفروع
- `branch`: الفرع (hr.department)
- `branch_type`: نوع الفرع (branches/governorates)
- `city_id`: المدينة
### 3. `relation.settings` - إعدادات صلة القرابة
- `relation_type`: نوع الصلة (son/daughter/mother/replacement_mother/other relation)
- `age_difference`: الفرق في العمر
### 4. `location.settings` - إعدادات الموقع
- `location_type`: نوع الموقع (member/mother_location)
- `is_benefit`: هل يستفيد؟
- `is_far_from_family`: بعيد عن الأسرة؟
### 5. `attachments.settings` - إعدادات المرفقات
- `attach_type`: نوع المرفق (family_attach/member_attach/income_attach/etc.)
- `is_required`: مطلوب؟
- `is_default`: افتراضي؟
- `show_in_portal`: عرض في البوابة؟
### 6. `education.settings` - إعدادات التعليم
- إعدادات المستويات التعليمية، الفصول، النتائج، التخصصات
### 7. `job.settings` - إعدادات الوظائف
- قائمة الوظائف المتاحة
### 8. `death.reason.settings` - إعدادات أسباب الوفاة
- قائمة أسباب الوفاة
---
## 🔄 العمليات المجدولة (Scheduled Actions)
### 1. **Recurrence Visit Workflow Scheduler**
- **التردد:** يومي
- **الوظيفة:** `create_scheduled_visit()`
- **الوصف:** إنشاء زيارات مجدولة تلقائياً حسب إعدادات أنواع الزيارات
### 2. **Notification: Expiry date Attachment**
- **التردد:** يومي
- **الوظيفة:** `send_expiry_date_notification()`
- **الوصف:** إرسال إشعارات للمرفقات المنتهية الصلاحية
### 3. **Update Data Auto (Daily)**
- **التردد:** يومي
- **الوظيفة:** `update_data_automatically()`
- **الوصف:** تحديث البيانات تلقائياً (مثل الأعمار، الحالات)
### 4. **Check Temporarily Exception**
- **التردد:** يومي
- **الوظيفة:** `action_auto_exception()`
- **الوصف:** التحقق من الاستثناءات المؤقتة المنتهية
### 5. **Check Member Temporarily Exception**
- **التردد:** يومي
- **الوظيفة:** `action_auto_exception()` (للأعضاء)
- **الوصف:** التحقق من استثناءات الأعضاء المؤقتة
### 6. **Send Expiring Salary Attachments Notifications**
- **التردد:** يومي
- **الوظيفة:** `action_send_attachment_expiry_email()`
- **الوصف:** إرسال إشعارات لشهادات الراتب المنتهية الصلاحية
---
## 📊 التقارير
### 1. **Benefit Report** (`benefit_report.py`)
- تقرير شامل عن الأسرة المستفيدة
### 2. **Family Bank Report** (`family_bank_report.py`)
- تقرير عن الحسابات البنكية للأسر
---
## 🎨 الواجهات (Views)
### النماذج الرئيسية:
- `benefit_view.xml`: واجهة ملف الأسرة
- `family_members.xml`: واجهة أعضاء الأسرة
- `service_request.xml`: واجهة طلبات الخدمات
- `visit.xml`: واجهة الزيارات
- `payment_order.xml`: واجهة أوامر الدفع
- `family_expense_view.xml`: واجهة مصروفات الأسرة
- `generate_reports.xml`: واجهة التقارير
### الإعدادات:
- `benefit_config_view.xml`: إعدادات الاستفادة
- `services_settings.xml`: إعدادات الخدمات
- `education_settings.xml`: إعدادات التعليم
- `family_validation_setting.xml`: إعدادات التحقق
---
## 🧙‍♂️ المعالجات (Wizards)
### 1. **Researcher Wizard** (`researcher_wizard.py`)
- تعيين باحث للأسرة أو العضو
### 2. **Suspend Reason Wizard** (`suspend_reason_wizard.py`)
- إدخال سبب الإيقاف
### 3. **Exception Wizard** (`exception_wizard.py`)
- إدخال معلومات الاستثناء
### 5. **Entity Refused Wizard** (`entity_refused_wizard.py`)
- إدخال سبب الرفض
### 6. **Entity Black List Wizard** (`entity_black_list_wizard.py`)
- إضافة للقائمة السوداء
### 7. **Visit Location OTP Wizard** (`visit_location_otp_wizard.py`)
- التحقق من OTP للزيارة
### 8. **Visit Location Refused Wizard** (`visit_location_refused_wizard.py`)
- إدخال سبب رفض الزيارة
### 9. **Family Bank Report Wizard** (`family_bank_report_wizard.py`)
- معالج تقرير الحسابات البنكية
### 10. **Service Refuse Reason Wizard** (`service_refuse_reason_wizard.py`)
- إدخال سبب رفض الخدمة
### 11. **Reason For Return Wizard** (`reason_for_return_wizard.py`)
- إدخال سبب الإرجاع
---
## 📧 القوالب البريدية
### 1. **Benefit Email Templates**
- قوالب إرسال الإشعارات للأسر
### 2. **Benefit Services Email Templates**
- قوالب إشعارات الخدمات
### 3. **Visit Email Templates**
- قوالب إشعارات الزيارات
---
## 🔗 التكاملات
### 1. **مع المحاسبة (Account)**
- إنشاء قيود محاسبية للمصروفات
- ربط أوامر الدفع بدفاتر اليومية
- تتبع المدفوعات
### 2. **مع المبيعات (Sale)**
- ربط الخدمات بطلبات المبيعات
### 3. **مع المشتريات (Purchase)**
- ربط الخدمات بطلبات الشراء
### 4. **مع الموارد البشرية (HR)**
- ربط الباحثين بالموظفين
- ربط الفروع بالأقسام
### 5. **مع الاستبيانات (Survey)**
- ربط الزيارات باستبيانات التقييم
### 6. **مع الموقع (Website)**
- بوابة المستفيدين
- عرض الخدمات المتاحة
---
## 📈 إحصائيات البيانات
بناءً على فحص البيانات في النظام:
- **عدد الأسر المستفيدة:** 18
- **عدد أعضاء الأسر:** 40
- **عدد طلبات الخدمات:** 23
- **عدد الزيارات:** 18
- **عدد تأكيدات المصروفات:** 8
---
## 🎯 الميزات الرئيسية
### 1. **إدارة شاملة للأسر المستفيدة**
- تسجيل كامل لمعلومات الأب والأم والأعضاء
- تتبع الحالات الاجتماعية والتعليمية والصحية
- حساب تلقائي للأعمار والحالات
### 2. **نظام ذكي لتحديد الاستفادة**
- حساب تلقائي لحالة الاستفادة لكل عضو
- قواعد معقدة تعتمد على العمر، الجنس، التعليم، العمل، الدخل
- دعم الاستثناءات المؤقتة والدائمة
### 3. **إدارة متقدمة للخدمات**
- أنواع خدمات متعددة (إيجار، أجهزة، زواج، إلخ)
- حدود وقيود مرنة حسب الفئة وعدد الأعضاء
- نظام موافقات متعدد المستويات
### 4. **نظام زيارات متطور**
- زيارات يدوية وتلقائية
- مصادقة OTP للزيارات
- استبيانات تقييم مرتبطة
### 5. **إدارة مالية متكاملة**
- حساب المصروفات الشهرية (نقدي، وجبات، ملابس)
- أوامر دفع متعددة الخدمات
- تكامل كامل مع المحاسبة
### 6. **تقارير وتحليلات**
- تقارير شاملة عن الأسر
- تقارير الحسابات البنكية
- إحصائيات متعددة
### 7. **بوابة المستفيدين**
- واجهة للمستفيدين لتقديم الطلبات
- متابعة حالة الطلبات
- رفع المرفقات
---
## 🔧 الصيانة والتطوير
### نقاط القوة:
✅ نظام شامل ومتكامل
✅ قواعد عمل معقدة ومرنة
✅ تكامل جيد مع موديولات Odoo الأخرى
✅ واجهات مستخدم منظمة
✅ نظام أمان قوي
### نقاط التحسين المحتملة:
⚠️ بعض الكود المعلق (commented code) يحتاج تنظيف
⚠️ بعض الحقول المكررة يمكن توحيدها
⚠️ يمكن تحسين الأداء في بعض الاستعلامات المعقدة
---
## 📝 الخلاصة
موديول `odex_benefit` هو نظام شامل ومتطور لإدارة المنح والمساعدات، يوفر:
- إدارة كاملة للأسر المستفيدة وأعضائها
- نظام ذكي لتحديد الاستفادة
- إدارة متقدمة للخدمات والطلبات
- نظام زيارات متطور
- إدارة مالية متكاملة
- تقارير وتحليلات شاملة
النظام مصمم بشكل احترافي ويوفر مرونة عالية في التكوين والإعدادات.
---
**تاريخ المراجعة:** 2025-01-08
**المراجع:** AI Assistant
**الإصدار:** 1.0

View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
from . import controllers
from . import models
from . import wizards
from . import reports

View File

@ -0,0 +1,75 @@
{
'name': 'Odex Benefit Managment',
'category': 'Grant Managment',
'summary': '<Grant Benefit Management for takaful Project >',
'version': '1.0',
'sequence': 4,
'website': 'http://exp-sa.com',
'license': 'GPL-3',
'author': 'Expert Ltd',
'depends': ['base', 'survey', 'takaful_core', 'website', 'account', 'report_xlsx', 'sale', 'product', 'stock', 'hr',
'purchase', 'web_google_maps', 'odex25_account_payment_fix', 'otp_sms_auth_custom'],
'data': [
'security/security_view.xml',
'security/ir.model.access.csv',
'data/scheduled_actions.xml',
'data/server_actions.xml',
'data/email_temps.xml',
'data/visits_types_data.xml',
'views/template.xml',
'views/benefit_view.xml',
'views/users_inherit.xml',
'views/committees_view.xml',
'views/branch_inherit.xml',
'views/family_members.xml',
'views/family_complaints.xml',
'views/education_status_views.xml',
'views/education_period.xml',
'views/seasonal_service_view.xml',
'wizards/researcher_wizard.xml',
'wizards/suspend_reason_wizard.xml',
'wizards/exception_wizard.xml',
'views/visit.xml',
'views/main_service.xml',
'views/member_location.xml',
'views/family_validation_setting.xml',
'views/ir_attachment_inherit.xml',
'views/changes_requests.xml',
'views/education_settings.xml',
'views/payment_order.xml',
# 'views/res_config_settings_view.xml',
# 'views/benefit_expenses_view.xml',
'views/sms_view.xml',
'reports/benefit_template.xml',
'views/benefit_services_view.xml',
'views/family_expense_view.xml',
'views/family_expense_line_view.xml',
'views/services_settings.xml',
'views/service_request.xml',
'views/benefit_config_view.xml',
'views/generate_reports.xml',
'views/service_refuse_reason.xml',
'views/job_settings_views.xml',
'views/death_reason_settings_views.xml',
'views/res_country.xml',
'templates/benefit_email.xml',
'data/sequence_data.xml',
'wizards/entity_refused_wizard_view.xml',
'wizards/entity_black_list_wizard_view.xml',
'wizards/service_refuse_reason_wizard.xml',
'wizards/reason_for_return_wizard.xml',
'wizards/visit_location_otp_wizard_view.xml',
'views/benefit_vehicle_model.xml',
'wizards/visit_location_refused_wizard_view.xml',
'wizards/family_bank_report_wizard.xml',
'views/visit_survey.xml',
'views/actions_and_menus.xml',
'reports/family_bank_report.xml',
],
'external_dependencies': {
'python': ['num2words'],
},
}

View File

@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
from . import benefit
from . import benefit_services
from . import attchment_preview
from . import create_portal_account

View File

@ -0,0 +1,30 @@
import base64
from odoo import http
from odoo.http import request
import urllib.parse # For URL encoding
class MyAttachmentController(http.Controller):
@http.route('/browse/document/<int:id>', type='http', auth="public")
def browse_document(self, id):
model = 'ir.attachment'
attachment = request.env[model].sudo().browse(id)
if not attachment.exists() or not attachment.datas:
return request.not_found()
# Decode the file content
file_data = base64.b64decode(attachment.datas)
file_mimetype = attachment.mimetype or 'application/octet-stream'
# URL-encode the filename for non-ASCII characters
filename = urllib.parse.quote(attachment.name)
# Set HTTP headers with the URL-encoded filename
http_headers = [
('Content-Type', file_mimetype),
('Content-Length', str(len(file_data))),
('Content-Disposition', f'inline; filename*=UTF-8\'\'{filename}')
]
return request.make_response(file_data, headers=http_headers)

View File

@ -0,0 +1,832 @@
# -*- coding: utf-8 -*-
from odoo.addons.web.controllers.main import serialize_exception
import re
from odoo.tools.translate import _
from odoo.http import request
import base64
import json
from odoo import http, modules
from odoo.addons.takaful_rest_api.controllers.main import *
_logger = logging.getLogger(__name__)
class BenefitPortal(http.Controller):
@staticmethod
def get_server_error(error):
x = False
if len(error.args) == 2:
x, y = error.args
x = re.sub('\n', '', x)
else:
x = error.args
text = (_("Contact Admin"))
message = "%s, %s" % (x, text)
return message
@staticmethod
def get_attachment(attachment_id):
attachment = request.env['ir.attachment'].sudo().search(
[('id', '=', attachment_id)])
if attachment:
result = ([attachment.id, attachment.name])
return result
@staticmethod
def get_validation_error(field_id):
filed = field_id.replace('_', ' ')
result = ({'status': False, 'msg': (
_('Enter The ' + filed)), 'data': {'field': field_id}})
return result
@staticmethod
def get_validation_image(FileStorage):
FileExtension = FileStorage.filename.split('.')[-1].lower()
ALLOWED_IMAGE_EXTENSIONS = ['jpg', 'pdf', 'png', 'jpeg']
if FileExtension not in ALLOWED_IMAGE_EXTENSIONS:
result = {'status': False, 'message': _(
"Only allowed files with extension: %s" % (
",".join(ALLOWED_IMAGE_EXTENSIONS)))}
return result
else:
pass
####################### Get function #####################
# Types
@http.route('/benefit/types/<key>', methods=["GET"], type='http', auth='public')
def get_benefit_types_data(self, key):
# Update context to add language
context = request.env.context.copy()
context.update({'lang': u'ar_001'})
request.env.context = context
try:
model = []
if 'items' in key:
model.append('benefit.housing.rooms.items')
if 'insurance' in key:
model.append('insurance.type')
if 'insurance_company' in key:
model.append('insurance.company')
if 'specialization' in key:
model.append('specialization.specialization')
if 'bank' in key:
model.append('res.bank')
if 'sport' in key:
model.append('sport.type')
if 'labor' in key:
model.append('domestic.labor')
if 'housing' in key:
# cloth.size
model.append('benefit.housing')
if 'uom' in key:
model.append('product.uom')
if 'cloth_size' in key:
model.append('cloth.size')
if 'cloth_type' in key:
model.append('cloth.type')
if 'associations' in key:
# Todo add filter in other.associations
model.append('other.associations')
if 'cat_need' in key:
# Todo add filter in needs.categories
model.append('needs.categories')
if model:
main_obj = {}
results = []
# dict_obj = {}
for k in model:
result = request.env[k].sudo().search([])
name = k.replace('.', '_')
if result:
results.append(
({name: [{'id': s.id, 'name': s.name} for s in result]}))
else:
results.append(({name: False}))
main_obj['result'] = results
# results.append(dict_obj)
return json.dumps(main_obj)
except Exception as e:
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
# Benefit Profile
@http.route('/benefit/profile', auth='public', website=True, csrf=False, methods=['GET'])
# TODO : ADD payment history in benefit Screen
def get_benefit(self):
try:
benefit = request.env['grant.benefit'].sudo().search(
[('user_id', '=', request.session.uid)])
print(benefit)
for rec in benefit:
benefit = rec
li = ['name', 'id_number', 'id_expiry', 'gender', 'marital_status', 'birth_date', 'family_id', 'bank_id',
'iban',
'email', 'phone', 'country_id', 'city_id', 'street', 'location', 'id_number_attach', 'iban_attach']
follower = request.env['grant.benefit'].sudo().search(
[('responsible_id', '=', benefit.id)])
lif = ['name', 'gender', 'responsible', 'birth_date',
'id_number', 'id_number_attach', 'status']
benefit_need = request.env['benefits.needs'].sudo().search(
[('benefit_id', '=', benefit.id)])
lneed = ['name', 'category_name', 'completion_ratio', 'state']
if benefit:
follower_list = []
for followers in follower.read(lif):
follower_list.append(followers)
benefit_needs = []
for need in benefit_need.read(lneed):
benefit_needs.append(need)
dicts = {}
keys = []
values = []
for i in benefit.read(li):
for k, v in i.items():
if k == 'id_number_attach':
keys.append(k)
values.append(self.get_attachment(v))
else:
keys.append(k)
values.append(v)
keys.append('follower')
values.append(follower_list)
keys.append('needs')
values.append(benefit_needs)
for i in keys:
dicts[i] = values[keys.index(i)]
data = {'status': True, 'msg': (
_('Benefit Found')), 'data': dicts}
else:
data = {'status': False, 'msg': (
_('Benefit not Found')), 'data': False}
return json.dumps(data)
except Exception as e:
import traceback
print(traceback.format_exc())
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
# Verify the address and the residential unit and add the beneficiary to it if it exists
@http.route('/benefit/check_address', auth='public', website=True, csrf=False, methods=['GET'])
def get_address_id(self, housing_number=False, **kw):
li = ['city_id', 'block', 'street', 'house_number', 'floor', 'rent_amount', 'housing_type', 'property_type',
'lat', 'lon', 'rooms_number', 'water_bill_account_number', 'electricity_bill_account_number']
try:
if not housing_number:
data = {'status': False, 'msg': (
_('Enter Your Residential unit Number')), 'data': {}}
else:
address = request.env['benefit.housing'].sudo().search(
[('housing_number', '=', housing_number)])
# for addres in address:
if address:
data = {'status': True, 'msg': (_('You have address')),
'data': address.read(li)}
else:
data = {'status': True, 'msg': (_('No address')),
'data': {}}
return json.dumps(data)
except Exception as e:
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
@http.route('/benefit/all_support', auth='public', website=True, csrf=False, methods=['GET'])
def get_all_support(self):
try:
benefit = request.env['grant.benefit'].sudo().search(
[('user_id', '=', request.session.uid)])
li = ['name.name', 'follower_type',
'birth_date', 'gender', 'name.responsible']
if benefit:
benefits = request.env['benefit.followers'].sudo().search(
[('benefit_id', '=', benefit.id)])
if benefits:
data = {'status': True, 'msg': (
_('Records Found ')), 'data': benefits.read(li)}
else:
data = {'status': False, 'msg': (
_('Records Not Found ')), 'data': {}}
else:
data = {'status': False, 'msg': (
_('Records Not Found ')), 'data': {}}
return json.dumps(data)
except Exception as e:
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
####################### POST function #####################
# complete Benefit Account
@http.route('/benefit/complete_benefit', auth='public', website=True, methods=['GET', 'POST'], csrf=False)
def get_complete_benefit(self, step, **kw):
benefit_id = request.env['grant.benefit'].sudo().search(
[('user_id', '=', request.session.uid)], limit=1)
if not benefit_id:
error = {'status': False, 'message': _("Not Found benefit ")}
return json.dumps(error)
step = int(step)
li = [
# first step values
'id', 'job_position', 'job_company', 'id_number_attach', 'id_expiry', 'marital_status', 'bank_id',
'iban', 'iban_attach', 'name_in_bank', 'followers_total', 'followers_out_total', 'instrument_number',
'instrument_attach',
# second step values
'city_id', 'house_number', 'block', 'street', 'floor', 'housing_type', 'property_type',
'lat', 'lon', 'house_images', 'rooms_number', 'water_bill_account_number', 'water_bill_account_attach',
'electricity_bill_account_number', 'electricity_bill_account_attach',
# step 3 values
'salary_type', 'salary_amount', 'salary_attach', 'isAssociated', 'associations_id', 'support_amount', 'support_description',
# step 4 values
'education_status', 'is_want_education', 'nearest_literacy_school', 'literacy_school_note', 'learning_expense',
'education_level', 'classroom', 'educational_institution_information', 'educational_institution_attach',
'specialization_ids', 'study_document_attached', 'case_study', 'graduation_status', 'graduation_date',
'interruption_date', 'reasons_for_interruption', 'acadimec_regsteration_attached', 'Transcript_attached',
'average', 'is_quran_memorize', 'quran_memorize_name', 'number_parts',
# step 5 values
'cloth_type', 'cloth_size', 'is_diseases', 'diseases_type', 'treatment_used', 'treatment_amount',
'is_treatment_amount_country', 'treatment_amount_country_Monthly', 'treatment_amount_country_description',
'treatment_amount_country_attach', 'is_disability', 'disability_type', 'disability_accessories',
'disability_attach', 'disability_amount', 'weight', 'height',
# step 6 values
'is_insurance', 'insurance_type', 'insurance_company', 'insurance_amount', 'insurance_attach',
# step 7 values
'is_sport', 'sport_type', 'sport_time', 'sport_club', 'subscription', 'sportswear', 'is_widows', 'is_divorcee']
benefit = ''
values = {}
benefit = {}
followers = {}
expenses = {}
salary = {}
associations = {}
sport = {}
try:
if step == 1:
fields = [
'id', 'job_position', 'job_company', 'id_number_attach', 'id_expiry', 'marital_status', 'bank_id',
'iban', 'iban_attach', 'name_in_bank', 'followers_total', 'followers_out_total', 'instrument_number',
'instrument_attach']
for field in fields:
if not kw.get(field, False):
error = self.get_validation_error(field)
return json.dumps(error)
values['function'] = kw.get('job_position')
if step == 2:
# 2 Housing
if not kw.get('house_number', False):
error = self.get_validation_error('house_number')
return json.dumps(error)
# A-Check if housing is available
address = request.env['benefit.housing'].sudo().search(
[('housing_number', '=', kw.get('house_number'))])
# B- if not housing Create an address and the housing unit
if not address:
values_address = {}
address = request.env['benefit.housing']
fields = [
'city_id', 'house_number', 'block', 'street',
'floor', 'housing_type', 'property_type',
'lat','lon', 'house_images', 'rooms_number',
'water_bill_account_number',
'water_bill_account_attach',
'electricity_bill_account_number',
'electricity_bill_account_attach',
]
attachments = [
'water_bill_account_attach',
'electricity_bill_account_attach'
]
for field in fields:
if not kw.get(field, False):
error = self.get_validation_error(field)
return json.dumps(error)
for attach in attachments:
if kw.get(attach, False):
error = self.get_validation_image(
kw.get(attach, False))
if error:
return json.dumps(error)
house_images = ['image', 'image_1',
'image_2', 'image_3', 'image_4']
index = 0
for image in list(http.request.httprequest.files.getlist('house_images')):
error = self.get_validation_image(image)
if error:
return json.dumps(error)
x= house_images[index]
values_address[x] = ""
values_address[x] = base64.b64encode(image.read())
index = index + 1
if index < 1 :
error = {'status': False, 'message': _("Please Upload More Than One Image")}
return json.dumps(error)
for field_name, field_value in kw.items():
if field_name not in attachments or field_name not in ['house_images']:
values_address[field_name] = field_value
for fname, fvalue in http.request.httprequest.files.items():
if fvalue:
file = fvalue.read()
if len(file) > 0:
values_address[fname] = base64.b64encode(file)
values_address['housing_number'] = values_address.pop('house_number')
address = address.sudo().create(values_address)
# address.sudo().write({'domestic_labor_ids': [(6, 0, [1, 2])]}) # Todo
address.sudo()._compute_get_name()
# c- Add the beneficiary to the housing unit by link the ID
values['housing_id'] = address.id
if step == 3:
fields = ['salary_type', 'salary_amount', 'salary_attach',
'isAssociated', 'associations_id',
'support_amount', 'support_description']
for field in fields:
if not kw.get(field, False):
error = self.get_validation_error(field)
return json.dumps(error)
# salary
salary['benefit_id'] = benefit_id.id
salary['salary_type'] = kw.get('salary_type')
salary['salary_amount'] = kw.get('salary_amount')
for fname , file in http.request.httprequest.files.items():
salary['salary_attach'] = base64.b64encode(file.read())
request.env['salary.line'].sudo().create(salary)
# associations
isAssociated = kw.get('isAssociated', False)
if isAssociated:
associations['benefit_id'] = benefit_id.id
associations['associations_ids'] = kw.get('associations_id')
associations['support_amount'] = kw.get('support_amount')
associations['associations_description'] = kw.get('support_description')
request.env['associations.line'].sudo().create(associations)
values['is_other_associations'] = isAssociated
if step == 4:
# Educational
fields = ['education_status']
for field in fields:
if not kw.get(field, False):
error = self.get_validation_error(field)
return json.dumps(error)
if kw.get('education_status', False) == 'illiterate':
if not kw.get('is_want_education', False):
return json.dumps({'status': False, 'msg': (_('is_want_education')), 'data': {}})
# Educational Level if education_status == educated
if kw.get('education_status', False) == 'educated':
if not kw.get('education_level', False):
return json.dumps({'status': False, 'msg': (_('education_level')), 'data': {}})
if not kw.get('classroom', False):
return json.dumps({'status': False, 'msg': (_('classroom')), 'data': {}})
if not kw.get('specialization_ids', False):
return json.dumps({'status': False, 'msg': (_('specialization')), 'data': {}})
if not kw.get('educational_institution_information', False):
return json.dumps(
{'status': False, 'msg': (_('educational_institution_information')), 'data': {}})
if not kw.get('case_study', False):
return json.dumps({'status': False, 'msg': (_('case_study')), 'data': {}})
if not kw.get('graduation_status', False):
return json.dumps({'status': False, 'msg': (_('graduation_status')), 'data': {}})
if kw.get('graduation_status', False) == 'graduated':
if not kw.get('graduation_date', False):
return json.dumps({'status': False, 'msg': (_('graduation_date')), 'data': {}})
if kw.get('graduation_status', False) == 'intermittent':
if not kw.get('reasons_for_interruption', False):
return json.dumps({'status': False, 'msg': (_('reasons_for_interruption')), 'data': {}})
if not kw.get('interruption_date', False):
return json.dumps({'status': False, 'msg': (_('interruption_date')), 'data': {}})
if not kw.get('study_document_attached', False):
return json.dumps({'status': False, 'msg': (_('study_document_attached')), 'data': {}})
if not kw.get('acadimec_regsteration_attached', False):
return json.dumps(
{'status': False, 'msg': (_('acadimec_regsteration_attached')), 'data': {}})
if not kw.get('Transcript_attached', False):
return json.dumps({'status': False, 'msg': (_('Transcript_attached')), 'data': {}})
if step == 5:
# health information#
if kw.get('is_diseases', False) == 'true':
if not kw.get('diseases_type', False):
return json.dumps({'status': False, 'msg': (_('diseases_type')), 'data': {}})
if not kw.get('treatment_used', False):
return json.dumps({'status': False, 'msg': (_('treatment_used')), 'data': {}})
if not kw.get('treatment_amount', False):
return json.dumps({'status': False, 'msg': (_('treatment_amount')), 'data': {}})
if kw.get('treatment_amount_country', False):
if not kw.get('treatment_amount_country_Monthly', False):
return json.dumps(
{'status': False, 'msg': (_('treatment_amount_country_Monthly')), 'data': {}})
if not kw.get('treatment_amount_country_description', False):
return json.dumps(
{'status': False, 'msg': (_('treatment_amount_country_description')), 'data': {}})
if not kw.get('treatment_amount_country_attach', False):
return json.dumps(
{'status': False, 'msg': (_('treatment_amount_country_attach')), 'data': {}})
# disability
if kw.get('is_disability', False):
if not kw.get('disability_type', False):
return json.dumps({'status': False, 'msg': (_('diseases_type')), 'data': {}})
if not kw.get('disability_accessories'
'', False):
return json.dumps({'status': False, 'msg': (_('treatment_used')), 'data': {}})
if not kw.get('treatment_amount', False):
return json.dumps({'status': False, 'msg': (_('treatment_amount')), 'data': {}})
if kw.get('treatment_amount_country', False):
if not kw.get('treatment_amount_country_Monthly', False):
return json.dumps(
{'status': False, 'msg': (_('treatment_amount_country_Monthly')), 'data': {}})
if not kw.get('treatment_amount_country_description', False):
return json.dumps(
{'status': False, 'msg': (_('treatment_amount_country_description')), 'data': {}})
if not kw.get('treatment_amount_country_attach', False):
return json.dumps(
{'status': False, 'msg': (_('treatment_amount_country_attach')), 'data': {}})
if step == 6:
if kw.get('is_insurance', False) == 'true':
if not kw.get('insurance_type', False):
return json.dumps({'status': False, 'msg': (_('insurance_type')), 'data': {}})
if not kw.get('insurance_company', False):
return json.dumps({'status': False, 'msg': (_('insurance_company')), 'data': {}})
if not kw.get('insurance_amount', False):
return json.dumps({'status': False, 'msg': (_('insurance_amount')), 'data': {}})
if not kw.get('insurance_attach', False):
return json.dumps({'status': False, 'msg': (_('insurance_attach')), 'data': {}})
if step == 7:
sport['benefit_id'] = benefit_id.id
sport['sport_type'] = kw.get('sport_type')
sport['sport_time'] = kw.get('sport_time')
sport['sport_club'] = kw.get('sport_club')
sport['subscription'] = kw.get('sport_club')
sport['sportswear'] = kw.get('sport_club')
# sport['Subtype'] = kw.get('Subtype')
# sport['sport_amount'] = kw.get('sport_amount')
# sport['sport_attendance'] = kw.get('sport_attendance')
# sport['sport_clothing'] = kw.get('sport_clothing')
# sport['sport_equipment'] = kw.get('sport_equipment')
request.env['sport.line'].sudo().create(sport)
for field_name, field_value in kw.items():
if field_name not in ['study_document_attached','support_description', 'salary_attach', 'salary_amount', 'salary_type', 'support_amount', 'associations_id', 'isAssociated','house_images', 'acadimec_regsteration_attached', 'Transcript_attached']:
values[field_name] = field_value
for fname, fvalue in http.request.httprequest.files.items():
if fname not in ['house_images','salary_attach']:
datas = base64.encodestring(fvalue.read())
if fname in ['iban_attach','id_number_attach','instrument_attach','water_bill_account_attach','electricity_bill_account_attach']:
file_name = fvalue.filename
attachment_data = {
'name':file_name,
'datas_fname':file_name,
'datas':datas,
'res_model':"grant.benefit",
}
attachment_id = request.env['ir.attachment'].create(attachment_data)
# if fname == 'id_number_attach' :
values[fname] = [(4,attachment_id.id)]
# else:
# values[fname] = datas
if step == 7:
values['state'] = 'waiting_approve'
if step <= 7 :
values['step'] = step + 1
print("benefit_id8888888888",benefit_id , type(benefit_id))
# import pprint
print(values)
benefit = benefit_id.sudo().write(values)
data = {'status': True, 'msg': (
_('data')), 'data': benefit_id.sudo().read([])}
return json.dumps(data)
except Exception as e:
import traceback
print(traceback.format_exc())
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
@http.route('/benefit/create_support', auth='public', website=True, csrf=False, methods=['POST'])
def get_create_support(self, **kw):
values = {}
message = ""
try:
check_id = request.env['grant.benefit'].sudo().search(
[('id_number', '=', kw.get('id_number'))])
parent = request.env['grant.benefit'].sudo().search(
[('user_id', '=', request.session.uid)])
if not check_id:
required_filed = ['name', 'relation',
'gender', 'birth_date', 'id_number_attach']
for filed in required_filed:
if not kw.get(filed, False):
error = self.get_validation_error(filed)
return json.dumps(error)
if not kw.get('id_number', False) or kw.get('id_number', False) == 0:
return json.dumps({'status': False, 'msg': (_('Enter Id Number')), 'data': {}})
for field_name, field_value in kw.items():
if field_name != "id_number_attach":
values[field_name] = field_value
#
for fname, fvalue in http.request.httprequest.files.items():
if fvalue:
file = fvalue.read()
if len(file) > 0:
values[fname] = base64.b64encode(file)
if kw.get('benefit_type') == 'orphan':
values['benefit_type'] = 'orphan'
if kw.get('benefit_type') == 'widow':
values['benefit_type'] = 'widow'
if kw.get('benefit_type') == 'other':
values['benefit_type'] = 'benefit'
values['responsible'] = kw.get('relation')
#
values['responsible_id'] = parent.id
# is_live_with_family
if kw.get('is_live_with_family'):
values['housing_id'] = parent.housing_id.id
for fname, fvalue in http.request.httprequest.files.items():
values[fname] = base64.b64encode(fvalue.read())
benefit = request.env['grant.benefit'].sudo().create(values)
if benefit:
data = {'status': True, 'msg': (
_('Record created ')), 'data': {}}
else:
data = {'status': False, 'msg': (
_('Record Not created ')), 'data': {}}
return json.dumps(data)
else:
return json.dumps({'status': False, 'msg': (_('Id Number Duplicated ')), 'data': {}})
except Exception as e:
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
@http.route('/benefit/profile/update', auth='public', website=True, csrf=False, methods=['PUT'])
def write_benefit_profile(self, **kw):
try:
benefit = request.env['grant.benefit'].sudo().search(
[('user_id', '=', request.session.uid)])
values = {}
li = ['name', 'id_number', 'id_expiry', 'gender', 'marital_status', 'birth_date', 'family_id', 'bank_id',
'iban',
'email', 'phone', 'country_id', 'city_id', 'street', 'location', 'id_number_attach', 'iban_attach']
if benefit:
# if benefit.state in ['edit_info']: Todo
for field_name, field_value in kw.items():
if field_name != "id_number_attach":
values[field_name] = field_value
for fname, fvalue in http.request.httprequest.files.items():
if fvalue:
file = fvalue.read()
if len(file) > 0:
values[fname] = base64.b64encode(file)
benefit.write(values)
data = {'status': True, 'msg': (
_('Benefit Found')), 'data': benefit.read(li)}
else:
data = {'status': False, 'msg': (
_('Benefit not Found')), 'data': False}
return json.dumps(data)
except Exception as e:
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
@http.route('/benefit/support/update', auth='public', website=True, csrf=False, methods=['PUT'])
def write_benefit_support(self, id, **kw):
# id of record
message = ""
try:
benefit = request.env['grant.benefit'].sudo().browse(int(id))
values = {}
li = ['f_name', 'g_name', 'parent', 'family', 'id_number', 'birth_date', 'age',
'gender', 'id', 'institution_id', 'partner_id', 'relation', 'state']
if benefit:
if benefit.state in ['draft']:
for field_name, field_value in kw.items():
if field_name != "id_number_attach":
values[field_name] = field_value
for fname, fvalue in http.request.httprequest.files.items():
if fvalue:
file = fvalue.read()
if len(file) > 0:
values[fname] = base64.b64encode(file)
benefit.write(values)
# if benefit.state == 'edit_info':
# benefit.action_finish_edit()
data = {'status': True, 'msg': (_('Benefit Account Updated successfully')),
'data': benefit.read(li)}
else:
data = {'status': False, 'msg': (
_('You Can Not Update Benefit Account ')), 'data': {}}
else:
data = {'status': False, 'msg': (
_('Benefit Account Not Found ')), 'data': {}}
return json.dumps(data)
except Exception as e:
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
@http.route('/benefit/request_need', auth='public', website=True, csrf=False, methods=['POST'])
def get_request_need(self, **kw):
values = {}
try:
benefit_ids = request.env['grant.benefit'].sudo().search(
[('user_id', '=', request.session.uid)])
benefit_id = False
for id in benefit_ids:
benefit_id = id
required_filed = ['need_category', 'description',
'f_amount', 'need_status', 'need_type_ids', 'need_attach']
for filed in required_filed:
if not kw.get(filed, False):
error = self.get_validation_error(filed)
return json.dumps(error)
for field_name, field_value in kw.items():
if field_name != "need_attach":
values[field_name] = field_value
# TO DO
for fname, fvalue in http.request.httprequest.files.items():
values[fname] = base64.b64encode(fvalue.read())
values['name'] = ("حوجة اليتيم " + benefit_id.name if benefit_id else '') # TODO
values['benefit_id'] = benefit_id.id if benefit_id else False
values['need_type_ids'] = [(6, 0, [1])] # TODO
values['city_id'] = benefit_id.city_id.id if benefit_id else False
values['benefit_need_type'] = 'special'
values['date'] = datetime.date.today()
benefit_needs = request.env['benefits.needs'].sudo().create(values)
if benefit_needs:
data = {'status': True, 'msg': (
_('Record created ')), 'data': {}}
else:
data = {'status': False, 'msg': (
_('Record Not created ')), 'data': {}}
return json.dumps(data)
except Exception as e:
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
@http.route('/portal/attachment', type='http', auth="public")
@serialize_exception
def download_documents(self, id, field, filename=None, **kw):
try:
model = 'grant.benefit'
res = request.env[model].sudo().browse(int(id))
if not filename:
filename = '%s_%s' % (model.replace('.', '_'), id)
x = str(field)
file = res.read([str(x)])
if file[0][x]:
fields = file[0][x]
filecontent = base64.b64decode(fields or '')
status, headers, content = request.env['ir.http'].binary_content(
model=model,
id=int(id),
field="%s" % (field),
default_mimetype='application/octet-stream',
env=request.env
)
mimetype = dict(headers).get('Content-Type')
return request.make_response(filecontent,
[('Content-Type', mimetype),
('Content-Disposition', "attachment")])
else:
return json.dumps({'status': False, 'msg': (_("No Attachment"))})
except Exception as e:
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
@http.route('/benefit/get_need_by_cat/<id>', auth='public', website=True, csrf=False, methods=['GET'])
def get_need_by_cat(self, id, **kw):
try:
result = []
needs_categories = request.env['needs.categories'].sudo().search([
('id', '=', int(id))])
for val in needs_categories.product_ids:
result.append(
{
"id": val.id,
"name": val.name
}
)
if result:
data = {'status': True, 'msg': (
_('Record Found ')), 'data': result}
else:
data = {'status': False, 'msg': (
_('Record Not Found ')), 'data': {}}
return json.dumps(data)
except Exception as e:
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
@http.route('/benefit/get_benefit_expenses/', auth='public', website=True, csrf=False, methods=['GET'])
def get_benefit_expenses(self, **kw):
try:
result = []
benefit_id = request.env['grant.benefit'].sudo().search(
[('user_id', '=', request.session.uid)], limit=1)
benefit_expenses = request.env['benefit.expenses'].sudo().search(
[('benefit_id', '=', int(benefit_id))])
for val in benefit_expenses:
result.append(
{
"name": val.name,
"expenses_type": self.get_selection_label('expenses_type',val.expenses_type),
"expenses_fees_type": self.get_selection_label('expenses_fees_type',val.expenses_fees_type),
"medicine_type": self.get_selection_label('medicine_type',val.medicine_type),
"diseases_type": self.get_selection_label('diseases_type',val.diseases_type),
"trans_type": self.get_selection_label('trans_type',val.trans_type),
"debt_reason": val.debt_reason,
"attach": val.attach,
"debt_type": self.get_selection_label('debt_type',val.debt_type),
"pandemics_explain": val.pandemics_explain,
"amount": val.amount,
"state": self.get_selection_label('state',val.state),
}
)
if result:
data = {'status': True, 'msg': (
_('Record Found ')), 'data': result}
else:
data = {'status': False, 'msg': (
_('Record Not Found ')), 'data': {}}
return json.dumps(data)
except Exception as e:
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
@http.route('/benefit/add_benefit_expenses/', auth='public', website=True, csrf=False, methods=['POST'])
def add_benefit_expenses(self, **kw):
try:
image_date = None
for image in list(http.request.httprequest.files.getlist('attach')):
image_date = base64.b64encode(image.read())
result = []
benefit_id = request.env['grant.benefit'].sudo().search(
[('user_id', '=', request.session.uid)], limit=1)
benefit_expenses = request.env['benefit.expenses']
date_created = {
"name": kw.get('name',False),
"benefit_id":benefit_id.id,
"expenses_type": kw.get('expenses_type',False),
"expenses_fees_type": kw.get('expenses_fees_type',False),
"medicine_type": kw.get('medicine_type',False),
"diseases_type": kw.get('diseases_type',False),
"trans_type": kw.get('trans_type',False),
"debt_reason": kw.get('debt_reason',False),
"attach":image_date,
"debt_type": kw.get('debt_type',False),
"pandemics_explain": kw.get('pandemics_explain',False),
"amount": kw.get('amount',False),
}
val = benefit_expenses.create(date_created)
return self.get_benefit_expenses()
except Exception as e:
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
def get_selection_label(self, field_name, field_value):
context = request.env.context.copy()
context.update({'lang': u'ar_001'})
request.env.context = context
if not field_name or not field_value:
return ''
return _(dict(request.env['benefit.expenses'].fields_get(allfields=[field_name])[field_name]['selection'])[field_value])

View File

@ -0,0 +1,383 @@
# -*- coding: utf-8 -*-
import re
from odoo.tools.translate import _
from odoo.http import request
import base64
import json
import logging
from odoo import http, modules
_logger = logging.getLogger(__name__)
class services(http.Controller):
def get_server_error(self, e):
x = False
if len(e.args) == 2:
x, y = e.args
x = re.sub('\n', '', x)
else:
x = e.args
text = (_("Contact Admin"))
message = "%s, %s" % (x, text)
return message
def get_validation_error(self, filed_id):
filed = filed_id.replace('_', ' ')
result = ({'status': False, 'msg': (
_('Enter The ' + filed)), 'data': {'filed': filed_id}})
return result
# restaurant
@http.route(['/services/restaurant/add_profile'], type="http", auth="public", website=True, method=['POST'],
csrf=False)
def add_restaurant_profile(self, **kw):
values = {}
li = ['name', 'surplus_type', 'zone', 'neighborhood',
'city_id', 'address', 'lat', 'lon']
for filed in li:
if not kw.get(filed, False):
error = self.get_validation_error(filed)
return json.dumps(error)
if request.session.uid:
partner = request.env['res.partner'].sudo().search(
[('user_id', '=', request.session.uid)])
values['partner_id'] = partner.id
for field_name, field_value in kw.items():
values[field_name] = field_value
values['surplus_type'] = [1, 2] # TODO
surplus = request.env['benefit.food.surplus'].sudo().create(values)
surplus.surplus_type = values['surplus_type']
if surplus:
data = {'status': True, 'msg': (
_('Record created ')), 'data': {}}
else:
data = {'status': False, 'msg': (
_('Record Not created ')), 'data': {}}
else:
data = {'status': False, 'msg': (_('need user')), 'data': {}}
return json.dumps(data)
# restaurant
@http.route(['/services/restaurant/add_food'], type="http", auth="public", website=True, method=['POST'],
csrf=False)
def add_restaurant_food(self, id, **kw):
values = {}
li = ['surplus_type', 'surplus_count', 'date_start',
'date_end', 'quantity', 'description']
for filed in li:
if not kw.get(filed, False):
error = self.get_validation_error(filed)
return json.dumps(error)
for field_name, field_value in kw.items():
values[field_name] = field_value
values['food_surplus_id'] = id
surplus = request.env['food.surplus.line'].sudo().create(values)
if surplus:
data = {'status': True, 'msg': (_('Record created ')), 'data': {}}
else:
data = {'status': False, 'msg': (
_('Record Not created ')), 'data': {}}
return json.dumps(data)
@http.route(['/services/restaurant/request_food'], type="http", auth="public", website=True, method=['POST'],
csrf=False)
def request_restaurant_food(self, id):
user_id = request.env['grant.benefit'].sudo().search(
[('user_id', '=', request.session.uid)])
food = request.env['food.surplus.line'].sudo().search([
('id', '=', id)])
if user_id:
foods = food.sudo().benefit_ids = [(4, user_id.id)]
print(foods)
if foods:
data = {'status': True, 'msg': (_('Request created ')), 'data': {}}
else:
data = {'status': False, 'msg': (_('Request Not created created ')), 'data': {}}
# # Todo: add is_available check
# TODO return barcode after request
# if food.is_available:
# data = {'status': True, 'msg': (_('Record created ')), 'data': {}}
# else:
# data = {'status': False, 'msg': (_('Record Not created ')), 'data': {}}
#
return json.dumps(data)
################ get function ##################
# ZkataAlfter
@http.route(['/services/zkat_alfter'], type="http", auth="public", website=True, method=['GET'],
csrf=False)
def get_all_zkat(self):
try:
data = request.env['receive.benefit.zkat'].sudo().search(
[('state', '=', 'receiving')])
data = {'status': True, 'msg': (_('zkat Found')),
'data': [(s.id, s.name, s.description, s.uint_price, str(s.date_from), str(s.date_to)) for s in data]}
return json.dumps(data)
except Exception as e:
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
@http.route(['/services/receive_zkat'], type="http", auth="public", website=True, method=['POST'], csrf=False)
def add_zakat(self, id, **kw):
values = {}
if not kw.get('donor_name', False):
return json.dumps({'status': False, 'msg': (_('donor_name')), 'data': {}})
if not kw.get('donation_type', False):
return json.dumps({'status': False, 'msg': (_('donation_type')), 'data': {}})
if kw.get('donation_type', False) == 'cash' or kw.get('donation_type', False) == 'both':
if not kw.get('amount', False):
return json.dumps({'status': False, 'msg': (_('amount')), 'data': {}})
if kw.get('donation_type', False) == 'material' or kw.get('donation_type', False) == 'both':
if not kw.get('quantity', False):
return json.dumps({'status': False, 'msg': (_('quantity')), 'data': {}})
values['receive_zkat_id'] = id
for field_name, field_value in kw.items():
if field_name == 'donor_name' or field_name == 'phone_number' or field_name == 'donation_type' or field_name == 'amount' or field_name == 'quantity':
values[field_name] = field_value
else:
continue
# todo online payment
collection = request.env['payment.collection.line'].sudo().create(
values)
if collection:
data = {'status': True, 'msg': (_('Record created ')), 'data': {}}
else:
data = {'status': False, 'msg': (
_('Record Not created ')), 'data': {}}
return json.dumps(data)
@http.route(['/services/food_basket'], type="http", auth="public", website=True, method=['GET'],
csrf=False)
def get_all_basket(self):
try:
data = request.env['receive.food.basket'].sudo().search(
[('state', '=', 'receiving')])
results = []
if data:
results.append(({'basket': [{'id': s.id, 'name': s.name, 'description': s.description,
'date_start': str(s.date_start), 'date_end': str(s.date_end)} for s in data]}))
data = {'status': True, 'data': results}
return json.dumps(data)
except Exception as e:
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
@http.route(['/services/add_food_basket'], type="http", auth="public", website=True, method=['POST'],
csrf=False)
def add_food_basket(self, id, **kw):
values = {}
if not kw.get('name', False):
return json.dumps({'status': False, 'msg': (_('name')), 'data': {}})
if not kw.get('phone_number', False):
return json.dumps({'status': False, 'msg': (_('phone_number')), 'data': {}})
if not kw.get('donation_type', False):
return json.dumps({'status': False, 'msg': (_('donation_type')), 'data': {}})
# if not kw.get('qty', False):
# return json.dumps({'status': False, 'msg': (_('qty')), 'data': {}})
values['food_basket_id'] = id
values['donation_method'] = 'outside'
for field_name, field_value in kw.items():
if field_name == 'name' or field_name == 'phone_number' or field_name == 'donation_type' or field_name == 'amount' or field_name == 'qty' or field_name == 'donation_method':
values[field_name] = field_value
else:
continue
collection = request.env['food.basket.line'].sudo().create(values)
if collection:
data = {'status': True, 'msg': (_('Record created ')), 'data': {}}
else:
data = {'status': False, 'msg': (
_('Record Not created ')), 'data': {}}
return json.dumps(data)
# Food Surplus
@http.route(['/services/reservation_food'], type="http", auth="public", website=True, method=['POST'],
csrf=False)
def reservation_food(self, id, benefit_id, **kw):
collection = request.env['food.surplus.line'].sudo().browse(int(id))
benefit = request.env['grant.benefit'].sudo().browse(int(benefit_id))
if collection:
if len(collection.benefit_ids) >= collection.surplus_count:
data = {'status': False, 'msg': (
_('Record Not created ')), 'data': {}}
else:
data = {'status': True, 'msg': (
_('Record created ')), 'data': {}}
for co in collection:
co.sudo().write({'benefit_ids': [(4, benefit.id)]})
else:
data = {'status': False, 'msg': (
_('Record Not found ')), 'data': {}}
return json.dumps(data)
@http.route(['/services/clubs'], type="http", auth="public", website=True, method=['GET'],
csrf=False)
def get_all_club(self):
try:
# todo : add is_available domain
clubs = request.env['benefit.club'].sudo().search(
[('is_available', '=', True)])
results = []
if clubs:
results.append(({'clubs': [{'id': s.id, 'name': s.name, 'description': s.description,
'subscription_amount': s.subscription_amount,
'programs_type': s.programs_type} for s in clubs]}))
data = {'status': True, 'data': results}
return json.dumps(data)
except Exception as e:
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
@http.route(['/services/club_subscription'], type="http", auth="none", website=True, method=['POST'],
csrf=False)
def add_subscription_request(self, id, **kw):
values = {}
li = ['name', 'phone_number', 'birth_date', 'city', 'lat', 'lon']
for filed in li:
if not kw.get(filed, False):
error = self.get_validation_error(filed)
return json.dumps(error)
for field_name, field_value in kw.items():
values[field_name] = field_value
# todo
# todo online payment
partner_id = request.env.user.partner_id
external_by_partner_id = request.env['external.benefits'].sudo().search(
[('partner_id', '=', partner_id.id)], limit=1)
external_by_phone = request.env['external.benefits'].sudo().search(
[('phone', '=', values['phone_number'])], limit=1)
external_id = external_by_partner_id or external_by_phone
if not external_id:
external_id = request.env['external.benefits'].sudo().create({
"name": values['name'],
"phone": values['phone_number'],
"birth_date": values['birth_date'],
"city_id": values['city'],
})
if not external_id and partner_id:
external_id = request.env['external.benefits'].sudo().create({
"name": partner_id.name,
"phone": partner_id.phone,
"birth_date": partner_id.birth_date,
"city_id": partner_id.city_id,
"partner_id": partner_id.id
})
subscription = None
if external_id:
subscription = request.env['external.request'].sudo().create({
"club_id": int(id),
"external_id": external_id.id,
"lat": values['lat'],
"lon": values['lon'],
})
if subscription:
data = {'status': True, 'msg': (_('Record created ')), 'data': {}}
else:
data = {'status': False, 'msg': (
_('Record Not created ')), 'data': {}}
return json.dumps(data)
@http.route(['/services/food'], type="http", auth="public", website=True, method=['GET'],
csrf=False)
def get_available_food_surplus(self):
try:
foods = request.env['food.surplus.line'].sudo().search(
[]) # ([('is_available', '=', True)])
results = []
if foods:
results.append(({'foods': [{'id': s.id, 'name': s.food_surplus_id.name,
'name_food': s.surplus_type.name,
'description': s.description,
'surplus_count': s.surplus_count, 'quantity': s.quantity, 'address':
s.food_surplus_id.address, 'date_start': str(s.date_start), 'date_end': str(s.date_end)} for s in foods]}))
data = {'status': True, 'data': results}
return json.dumps(data)
except Exception as e:
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
@http.route(['/services/loans'], type="http", auth="public", website=True, method=['GET'],
csrf=False)
def get_all_loans(self):
try:
loans = request.env['benefit.loans'].sudo().search(
[('state', '=', 'announced')])
results = []
if loans:
results.append(({'loans': [{'id': s.id, 'name': s.family_id.name, 'description': s.description,
'benefits_total': s.benefits_total,
'project_name': s.name, 'loan_amount': s.loan_amount, } for s in loans]}))
data = {'status': True, 'data': results}
return json.dumps(data)
except Exception as e:
_logger.error(str(e))
message = self.get_server_error(e)
data = {'status': False, 'msg': message}
return json.dumps(data)
#create_loan in backend
@http.route(['/services/create_loan'], type="http", auth="public", website=True, method=['POST'],
csrf=False)
def create_loan(self, **kw):
values = {}
# if not kw.get('phone_number', False):
# return json.dumps({'status': False, 'msg': (_('phone_number')), 'data': {}})
# if not kw.get('loan_amount', False):
# return json.dumps({'status': False, 'msg': (_('loan_amount')), 'data': {}})
# if not kw.get('installment_value', False):
# return json.dumps({'status': False, 'msg': (_('installment_value')), 'data': {}})
# if not kw.get('installment_number', False):
# return json.dumps({'status': False, 'msg': (_('installment_number')), 'data': {}})
for field_name, field_value in kw.items():
values[field_name] = field_value
loan = request.env['receive.benefit.loans'].sudo().create(values)
if loan:
data = {'status': True, 'msg': (_('Record created ')), 'data': {}}
else:
data = {'status': False, 'msg': (
_('Record Not created ')), 'data': {}}
return json.dumps(data)
# restaurant
@http.route(['/services/appliancesFurniture/receive'], type="http", auth="public", website=True, method=['POST'],
csrf=False)
def add_appliances(self, **kw):
values = {}
li = ['name', 'donor_name', 'phone_number', 'address', 'lat', 'lon', 'date_receipt', 'uom_id', 'product_qty',
'product_status', 'description']
for filed in li:
if not kw.get(filed, False):
error = self.get_validation_error(filed)
return json.dumps(error)
for field_name, field_value in kw.items():
if field_name not in ['image_1', 'image_2', 'image_3', 'image_4']:
values[field_name] = field_value
for fname, fvalue in http.request.httprequest.files.items():
if fvalue:
file = fvalue.read()
if len(file) > 0:
values[fname] = base64.b64encode(file)
values['donation_method'] = 'platform'
appliances = request.env['receive.appliances.furniture'].sudo().create(
values)
if appliances:
data = {'status': True, 'msg': (_('Record created ')), 'data': {}}
else:
data = {'status': False, 'msg': (
_('Record Not created ')), 'data': {}}
return json.dumps(data)

View File

@ -0,0 +1,179 @@
from odoo import http, _
from odoo.http import request
from odoo.addons.phone_validation.tools import phone_validation
import json
import random
class CreatePortalAccount(http.Controller):
@http.route('/create/portal/account', type="http", auth="public", csrf=False, methods=['POST'])
def create_portal_account(self, **kw):
try:
data = {}
applicant_name = kw.get('applicant_name')
applicant_relation = kw.get('relation_type')
first_name = kw.get('first_name')
second_name = kw.get('second_name')
login = kw.get('otp_mobile_phone')
email = kw.get('email')
account_type = kw.get('account_type')
relation_type = kw.get('relation_type')
password = str(random.randint(1000, 9999))
# Validate required fields
if not login:
data = {
'status': False,
'message': 'login is required.'
}
return json.dumps(data)
# Check if user already exists with the same otp_mobile_phone
existing_user = request.env['res.users'].sudo().search([('login', '=', login)], limit=1)
if existing_user:
existing_partner = existing_user.partner_id
is_family_or_beneficiary = existing_partner.is_family or existing_partner.is_benefit
is_donor_vendor_sponsor = existing_partner.is_donor or existing_partner.is_sponsor_portal or existing_partner.is_vendor
if is_family_or_beneficiary and account_type == 'donor':
message = _("This phone number is already registered as Family/Beneficiary and cannot be used for sponsor account!")
elif is_donor_vendor_sponsor and account_type == 'family':
message = _("This phone number is already registered as Donor/Sponsor and cannot be used for family account!")
else:
message = _('This phone number is already registered. Please use a different phone number.')
data = {
'status': False,
'message': message
}
return json.dumps(data)
country = request.env.company.country_id
formatted_phone = phone_validation.phone_format(
login,
country.code if country else None,
country.phone_code if country else None,
force_format='E164',
raise_exception=False).replace('+', '')
# Create partner first
Partner = request.env['res.partner'].sudo()
partner_vals = {
'name': f'{first_name} {second_name}',
'email': email,
'phone': formatted_phone,
}
partner = Partner.search([('phone', '=like', f'%{formatted_phone}')], limit=1)
if not partner:
partner = Partner.create(partner_vals)
else:
partner.write(partner_vals)
# Create user and link to partner (no reset password)
Users = request.env['res.users'].sudo()
user = Users.with_context(no_reset_password=True).create({
'name': partner.name,
'login': login,
'partner_id': partner.id,
'active': True,
})
# Set partner account_type
partner.set_partner_account_type(account_type)
# Update user fields similar to create_user and original flow
user.sudo().write({
'password': password,
'otp_mobile_phone': login,
'email': email,
'phone': formatted_phone,
'mobile': formatted_phone,
})
# Make the user as portal
user.sudo().write({
'groups_id': [(3, request.env.ref('base.group_user', False).id)],
})
user.sudo().write({
'groups_id': [(4, request.env.ref('base.group_portal', False).id)],
})
# Generate OTP and enable it
user.generate_otp()
user.otp_enabled = True
grant_benefit = False
# Only create a grant.benefit record for beneficiary/family account types
if account_type in ('beneficiary', 'family'):
benefit_data = {
'name': f'{first_name} {second_name}',
'father_name': first_name,
'father_family_name': second_name,
'sms_phone': login,
'email': email,
'is_from_portal': True,
'applicant_name': applicant_name,
'partner_id': partner.id,
'user_id': user.id,
'request_producer_relation': int(applicant_relation) if applicant_relation else False,
}
# Check relation type
if relation_type and int(relation_type):
relation_record = request.env['relation.settings'].sudo().search([('id', '=', relation_type)], limit=1)
if relation_record:
benefit_data.update({'request_producer_relation': relation_record.id})
# Create the grant.benefit record and let its create flow run
grant_benefit = request.env['grant.benefit'].sudo().with_context(force_website=True, is_benefit=True).create(benefit_data)
elif account_type == 'donor':
partner.write({
'is_donor': True,
'is_sponsor_portal': True,
})
# Return success response
data = {
'status': True,
'message': 'User and benefit record created successfully.',
'user_id': user.id,
'grant_benefit_id': grant_benefit.id if grant_benefit else False,
}
return json.dumps(data)
except Exception as e:
request.env.cr.rollback()
# Handle errors
data = {
'status': False,
'message': f'An error occurred: {str(e)}'
}
return json.dumps(data)
@http.route('/validate_otp', type='http', auth="public", website=True)
def validate_otp(self, **kw):
user = request.env['res.users'].sudo().browse(int(kw.get('user_id')))
otp = kw.get('otp')
if user:
is_valid = user.validate_otp(otp)
if is_valid:
user.sudo().write({'active': True})
# Commit before authentication
request.env.cr.commit()
# Authenticate the user properly
request.session.authenticate(request.db, user.login, otp)
# Redirect to the desired link
data = {
'status': True,
'url': '/web',
}
# Replace with your desired link
else:
# If OTP validation fails, return an error
data = {
'status': False,
'message': 'OTP not valid',
}
return request.make_response(json.dumps(data), headers={'Content-Type': 'application/json'})

View File

@ -0,0 +1,383 @@
<odoo>
<data noupdate="1">
<record id="visit_notification_template" model="mail.template">
<field name="name">Visit Assignment Notification</field>
<field name="model_id" ref="odex_benefit.model_visit_location"/>
<field name="subject">${object.benefit_id.name or 'New Visit Assigned'}</field>
<field name="lang">${object.create_uid.lang}</field>
<field name="auto_delete" eval="True"/>
<field name="body_html" type="html">
<table border="0" cellpadding="0" cellspacing="0"
style="padding-top: 16px; background-color: #F9F9F9; font-family: Verdana, Arial, sans-serif; color: #333; width: 100%; border-collapse: separate;">
<tr>
<td align="center">
<table border="0" cellpadding="0" cellspacing="0" width="600"
style="background-color: #fff; padding: 16px; border-collapse: separate;">
<tr>
<td style="font-size: 14px; line-height: 20px;">
<p>Hello,</p>
<p>A new visit has been assigned to you. Details are below:</p>
<ul>
<li>
<strong>Benefit File:</strong>
${object.benefit_id.name or 'N/A'}
</li>
<li>
<strong>Visit Number:</strong>
${object.name or object.id}
</li>
<li>
<strong>Visit Date:</strong>
${format_date(object.visit_date)}
</li>
</ul>
<p>Please check your dashboard for more details.</p>
<br/>
<p style="font-size: 11px; color: grey;">This is an automated message. Do not
reply.
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</field>
</record>
<!-- Attachment Expiration Email Template for family-->
<record id="attachment_expiration_family_email_template" model="mail.template">
<field name="name">Attachment Expiration</field>
<field name="model_id" ref="odex_benefit.model_grant_benefit"/>
<field name="email_from">
<![CDATA[${user.company_id.name} <${(user.company_id.email or user.partner_id.email or 'noreply@localhost')|safe}>]]></field>
<field name="email_to">${(object.get_researchers_email())|safe}</field>
<field name="email_cc">${(object.email)|safe}</field>
<field name="subject">Attachment Expiration</field>
<field name="body_html" type="html">
<table border="0" cellpadding="0" cellspacing="0"
style="padding-top: 16px; background-color: #F1F1F1; font-family:Verdana, Arial,sans-serif; color: #454748; width: 100%; border-collapse:separate;">
<tr>
<td align="center">
<table border="0" cellpadding="0" cellspacing="0" width="590"
style="padding: 16px; background-color: white; color: #454748; border-collapse:separate;">
<tbody>
<!-- HEADER -->
<tr>
<td align="center" style="min-width: 590px;">
<table border="0" cellpadding="0" cellspacing="0" width="590"
style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
<tr>
<td valign="middle">
</td>
<td valign="middle" align="right">
<img src="/logo.png?company=${object.create_uid.company_id.id}"
style="padding: 0px; margin: 0px; height: auto; width: 80px;"
alt="${object.create_uid.company_id.name}"/>
</td>
</tr>
<tr>
<td colspan="2" style="text-align:center;">
<hr width="100%"
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"/>
</td>
</tr>
</table>
</td>
</tr>
<!-- CONTENT -->
<tr>
<td align="center" style="min-width: 590px;">
<table border="0" cellpadding="0" cellspacing="0" width="590"
style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
<tr>
<td valign="top" style="font-size: 13px;">
<div>
<center>
Family ${object.name},
<br/>
<br/>
Please Update your attachments because some of them has
been expired!
<br/>
</center>
<br/>
</div>
</td>
</tr>
<tr>
<td style="text-align:center;">
<hr width="100%"
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"/>
</td>
</tr>
</table>
</td>
</tr>
<!-- FOOTER -->
<tr>
<td align="center" style="min-width: 590px;">
<table border="0" cellpadding="0" cellspacing="0" width="590"
style="min-width: 590px; background-color: white; font-size: 11px; padding: 0px 8px 0px 8px; border-collapse:separate;">
<tr>
<td valign="middle" align="left">
${object.create_uid.company_id.name}
</td>
</tr>
<tr>
<td valign="middle" align="left" style="opacity: 0.7;">
${object.create_uid.company_id.phone}
% if object.create_uid.company_id.email
|
<a href="'mailto:%s' % ${object.create_uid.company_id.email}"
style="text-decoration:none; color: #454748;">
${object.create_uid.company_id.email}
</a>
% endif
% if object.create_uid.company_id.website
|
<a href="'%s' % ${object.create_uid.company_id.website}"
style="text-decoration:none; color: #454748;">
${object.create_uid.company_id.website}
</a>
% endif
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</field>
</record>
<!-- Schedule a visit -->
<record id="schedule_a_visit_email_template" model="mail.template">
<field name="name">Schedule a visit</field>
<field name="model_id" ref="odex_benefit.model_visit_location"/>
<field name="email_from">
<![CDATA[${user.company_id.name} <${(user.company_id.email or user.partner_id.email or 'noreply@localhost')|safe}>]]></field>
<field name="email_to">${(object.benefit_id.email)|safe}</field>
<field name="email_cc">${(object.get_researchers_email())|safe}</field>
<field name="subject">Schedule a visit</field>
<field name="body_html" type="html">
<table border="0" cellpadding="0" cellspacing="0"
style="padding-top: 16px; background-color: #F1F1F1; font-family:Verdana, Arial,sans-serif; color: #454748; width: 100%; border-collapse:separate;">
<tr>
<td align="center">
<table border="0" cellpadding="0" cellspacing="0" width="590"
style="padding: 16px; background-color: white; color: #454748; border-collapse:separate;">
<tbody>
<!-- HEADER -->
<tr>
<td align="center" style="min-width: 590px;">
<table border="0" cellpadding="0" cellspacing="0" width="590"
style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
<tr>
<td valign="middle">
</td>
<td valign="middle" align="right">
<img src="/logo.png?company=${object.create_uid.company_id.id}"
style="padding: 0px; margin: 0px; height: auto; width: 80px;"
alt="${object.create_uid.company_id.name}"/>
</td>
</tr>
<tr>
<td colspan="2" style="text-align:center;">
<hr width="100%"
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"/>
</td>
</tr>
</table>
</td>
</tr>
<!-- CONTENT -->
<tr>
<td align="center" style="min-width: 590px;">
<table border="0" cellpadding="0" cellspacing="0" width="590"
style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
<tr>
<td valign="top" style="font-size: 13px;">
<div>
<center>
We want to schedule visit date with Researcher
${(object.researcher_ids[1])}
<br/>
<br/>
<br/>
to family ${(object.benefit_id.name)}
in this location
<a href="${object.get_url_local()}" target="_blank"
style="color: blue; text-decoration: underline;">
${object.get_url_local()}
</a>
</center>
<br/>
</div>
</td>
</tr>
<tr>
<td style="text-align:center;">
<hr width="100%"
style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"/>
</td>
</tr>
</table>
</td>
</tr>
<!-- FOOTER -->
<tr>
<td align="center" style="min-width: 590px;">
<table border="0" cellpadding="0" cellspacing="0" width="590"
style="min-width: 590px; background-color: white; font-size: 11px; padding: 0px 8px 0px 8px; border-collapse:separate;">
<tr>
<td valign="middle" align="left">
${object.create_uid.company_id.name}
</td>
</tr>
<tr>
<td valign="middle" align="left" style="opacity: 0.7;">
${object.create_uid.company_id.phone}
% if object.create_uid.company_id.email
|
<a href="'mailto:%s' % ${object.create_uid.company_id.email}"
style="text-decoration:none; color: #454748;">
${object.create_uid.company_id.email}
</a>
% endif
% if object.create_uid.company_id.website
|
<a href="'%s' % ${object.create_uid.company_id.website}"
style="text-decoration:none; color: #454748;">
${object.create_uid.company_id.website}
</a>
% endif
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</field>
</record>
<!--Visit Location OTP Email-->
<record id="visit_location_otp_email_template" model="mail.template">
<field name="name">Visit Location OTP Email</field>
<field name="model_id" ref="odex_benefit.model_visit_location"/>
<field name="subject">Your OTP Code</field>
<field name="body_html" type="html">
<table border="0" cellpadding="0" cellspacing="0"
style="padding-top:16px;background-color:#F9F9F9;font-family:Verdana,Arial,sans-serif;color:#333;width:100%;border-collapse:separate;">
<tr>
<td align="center">
<table border="0" cellpadding="0" cellspacing="0" width="600"
style="background-color:#fff;padding:24px;border-radius:8px;border-collapse:separate;">
<tr>
<td style="font-size:14px;line-height:20px;">
<p>Hello,</p>
<p>Your OTP for confirming visit <strong>${object.name}</strong> is:
</p>
<!-- OTP Block -->
<div style="text-align:center;margin:20px 0;">
<span style="display:inline-block;background-color:#2c3e50;color:#ffffff;
font-size:24px;font-weight:bold;padding:12px 24px;
border-radius:6px;letter-spacing:3px;">
${object.otp_code}
</span>
</div>
<p>This code is valid for <strong>
${object.visit_types.otp_validity_minutes or 5}
</strong> minutes.
</p>
<br/>
<p>Regards,
<br/>
<strong>${user.company_id.name}</strong>
</p>
<br/>
<p style="font-size:11px;color:grey;">
This is an automated message. Please do not reply.
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</field>
</record>
<!--Visit Location OTP SMS-->
<record id="visit_location_otp_sms_template" model="sms.template">
<field name="name">Visit Location OTP</field>
<field name="model_id" ref="odex_benefit.model_visit_location"/>
<field name="body">
Hello Your verification code for ${object.name} visit is ${object.otp_code}.
It is valid for ${object.visit_types.otp_validity_minutes or 5} minutes.
</field>
</record>
<!--Visit Location Survey SMS-->
<record id="visit_location_survey_sms_template" model="sms.template">
<field name="name">Visit Location Survey SMS</field>
<field name="model_id" ref="odex_benefit.model_visit_location"/>
<field name="body">
Dear family, please complete the evaluation form for visit ${object.name}: ${object.survey_url}
</field>
</record>
<!--Visit Location Survey Email-->
<record id="visit_location_survey_email_template" model="mail.template">
<field name="name">Visit Location Survey Email</field>
<field name="model_id" ref="odex_benefit.model_visit_location"/>
<field name="subject">Family Evaluation Survey - ${object.name}</field>
<field name="body_html" type="html">
<div style="background-color:#f9f9f9;padding:30px;
font-family:Arial,sans-serif;color:#333;
font-size:16px;line-height:24px;">
<p>Hello,</p>
<p>Please complete the evaluation form for your visit:
<strong>${object.name}</strong>.
</p>
<!-- CTA Button -->
<p style="text-align:center;margin:30px 0;">
<a href="${object.survey_url}"
style="display:inline-block;
padding:14px 32px;
background:linear-gradient(135deg,#e6f0ff,#cce0ff);
color:#003366;
font-size:16px;
font-weight:600;
text-decoration:none;
border-radius:6px;
border:1px solid #99c2ff;
box-shadow:0 4px 6px rgba(0,0,0,0.05);">
Open Survey
</a>
</p>
<p>Thank you for your cooperation.
<br/>
<strong>${user.company_id.name}</strong>
</p>
<hr style="border:none;border-top:1px solid #ddd;margin:30px 0;"/>
<p style="font-size:12px;color:#888;">
This is an automated message. Please do not reply.
</p>
</div>
</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data noupdate="0">
<!-- Scheduler for Managing Sponsorship Workflow Every Day -->
<record id="scheduler_visit_workflow_action" forcecreate='True' model="ir.cron">
<field name="name">Recurrence Visit Workflow Scheduler</field>
<field name="user_id" ref="base.user_root" />
<field name="interval_number">1</field>
<field name="nextcall" eval="(DateTime.now() + relativedelta(days=1)).strftime('%Y-%m-%d 00:00:00')" />
<!-- <field name="nextcall" eval="(datetime.now() + timedelta(minutes=7)).strftime('%Y-%m-%d %H:%M:%S')"/>-->
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field name="doall" eval="False"/>
<field name="model_id" ref="model_grant_benefit"/>
<field name="code">model.create_scheduled_visit()</field>
<field name="state">code</field>
<field name="priority" eval="5" />
<field name="active" eval="True"/>
</record>
<!-- Cron for send notification for expiry date attachment for family-->
<record id="ir_cron_send_notification" model="ir.cron">
<field name="name">Notification: Expiry date Attachment</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field name="nextcall" eval="(DateTime.today() + relativedelta(hours=0, minutes=0)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="doall" eval="False"/>
<field name="model_id" ref="model_grant_benefit"/>
<field name="code">model.send_expiry_date_notification()</field>
<field name="state">code</field>
</record>
<record id="ir_cron_update_data_auto" model="ir.cron">
<field name="name">Update Data Auto (Daily)</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field name="nextcall" eval="(DateTime.today() + relativedelta(hours=0, minutes=0)).strftime('%Y-%m-%d 00:00:00')"/>
<field name="doall" eval="False"/>
<field name="model_id" ref="model_grant_benefit"/>
<field name="code">model.update_data_automatically()</field>
<field name="state">code</field>
</record>
<record id="ir_cron_auto_exception" model="ir.cron">
<field name="name">Check Temporarily Exception</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field name="nextcall" eval="(DateTime.today() + relativedelta(hours=0, minutes=0)).strftime('%Y-%m-%d 00:00:00')"/>
<field name="doall" eval="False"/>
<field name="model_id" ref="model_grant_benefit"/>
<field name="code">model.action_auto_exception()</field>
<field name="state">code</field>
</record>
<record id="ir_cron_auto_member_exception" model="ir.cron">
<field name="name">Check Member Temporarily Exception</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field name="nextcall" eval="(DateTime.today() + relativedelta(hours=0, minutes=0)).strftime('%Y-%m-%d 00:00:00')"/>
<field name="doall" eval="False"/>
<field name="model_id" ref="model_family_member"/>
<field name="code">model.action_auto_exception()</field>
<field name="state">code</field>
</record>
<record id="cron_send_attachment_expiry_emails" model="ir.cron">
<field name="name">Send Expiring Salary Attachments Notifications</field>
<field name="model_id" ref="model_salary_line"/>
<field name="state">code</field>
<field name="code">model.action_send_attachment_expiry_email()</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field name="active" eval="True"/>
</record>
</data>
</odoo>

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data noupdate="1">
<record id="sequence_benefit" model="ir.sequence">
<field name="name">Benefit Sequence</field>
<field name="code">benefit.sequence</field>
<field name="prefix">BP/</field>
<field eval="1" name="number_next"/>
<field eval="1" name="number_increment"/>
<field eval="False" name="use_date_range"/>
<field eval="False" name="company_id"/>
<field name="padding">5</field>
</record>
<record id="receive_zkat_sequence" model="ir.sequence">
<field name="name">Receive Zkat Sequence</field>
<field name="code">benefit.receive.zkat.sequence</field>
<field name="prefix">RZ/</field>
<field eval="1" name="number_next"/>
<field eval="1" name="number_increment"/>
<field eval="True" name="use_date_range"/>
<field eval="False" name="company_id"/>
<field name="padding">4</field>
</record>
<record id="zkat_sequence" model="ir.sequence">
<field name="name">Zkat Sequence</field>
<field name="code">benefit.zkat.sequence</field>
<field name="prefix">Z/</field>
<field eval="1" name="number_next"/>
<field eval="1" name="number_increment"/>
<field eval="True" name="use_date_range"/>
<field eval="False" name="company_id"/>
<field name="padding">4</field>
</record>
<!-- Sequence For Visit -->
<record id="visit_location_sequence" model="ir.sequence">
<field name="name">Visit Sequence</field>
<field name="code">visit.location.sequence</field>
<field name="prefix">VT</field>
<field eval="1" name="number_next"/>
<field eval="1" name="number_increment"/>
<field eval="True" name="use_date_range"/>
<field eval="False" name="company_id"/>
<field name="padding">5</field>
</record>
<!-- Sequence for services requests -->
<record id="service_request_sequence" model="ir.sequence">
<field name="name">Services Requests Sequence</field>
<field name="code">service.request.sequence</field>
<field name="prefix">R/</field>
<field eval="1" name="number_next"/>
<field eval="1" name="number_increment"/>
<field eval="True" name="use_date_range"/>
<field eval="False" name="company_id"/>
<field name="padding">4</field>
</record>
<!-- Sequence for Seasonal services-->
<record id="seasonal_service_sequence" model="ir.sequence">
<field name="name">Seasonal Services Sequence</field>
<field name="code">seasonal.service.sequence</field>
<field name="prefix">R/</field>
<field eval="1" name="number_next"/>
<field eval="1" name="number_increment"/>
<field eval="True" name="use_date_range"/>
<field eval="False" name="company_id"/>
<field name="padding">4</field>
</record>
<!-- Sequence for payment orders -->
<record id="payment_orders_sequence" model="ir.sequence">
<field name="name">Payment Orders Sequence</field>
<field name="code">payment.orders.sequence</field>
<field name="prefix">P/</field>
<field eval="1" name="number_next"/>
<field eval="1" name="number_increment"/>
<field eval="True" name="use_date_range"/>
<field eval="False" name="company_id"/>
<field name="padding">4</field>
</record>
<!-- Sequence for Family Expense -->
<record id="family_expense_sequence" model="ir.sequence">
<field name="name">Family Expense Sequence</field>
<field name="code">family.expense.sequence</field>
<field name="prefix">EXP/</field>
<field eval="1" name="number_next"/>
<field eval="1" name="number_increment"/>
<field eval="True" name="use_date_range"/>
<field eval="False" name="company_id"/>
<field name="padding">4</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Used to bring a menu inside action menu -->
<record id="server_action_accounting_transfer" model="ir.actions.server">
<field name="name">Accounting Transfer</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.action_accounting_transfer()
</field>
</record>
<record id="server_action_seasonal_service_exchange_orders" model="ir.actions.server">
<field name="name">Exchange orders</field>
<field name="model_id" ref="odex_benefit.model_seasonal_service"/>
<field name="binding_model_id" ref="odex_benefit.model_seasonal_service"/>
<field name="state">code</field>
<field name="code">
action = records.action_create_payment_order()
</field>
</record>
<record id="action_assign_visit_sequence" model="ir.actions.server">
<field name="name">Assign Visit Sequence</field>
<field name="model_id" ref="odex_benefit.model_visit_location"/>
<field name="binding_model_id" ref="odex_benefit.model_visit_location"/>
<field name="state">code</field>
<field name="code">
action = records.assign_sequence_to_records()
</field>
<field name="binding_type">action</field>
</record>
<record id="action_assign_benefit_sequence" model="ir.actions.server">
<field name="name">Re-Assign Benefit Sequence</field>
<field name="model_id" ref="odex_benefit.model_grant_benefit"/>
<field name="binding_model_id" ref="odex_benefit.model_grant_benefit"/>
<field name="state">code</field>
<field name="code">
action = records.assign_sequence_to_all()
</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="initial_visit" model="visits.types">
<field name="name">أولية</field>
<field name="creation_method">automatic</field>
<field name="recurrence_interval">0</field>
<field name="otp_verification">True</field>
<field name="otp_validity_minutes">1</field>
</record>
<record id="recurrence_visit" model="visits.types">
<field name="name">دورية</field>
<field name="creation_method">automatic</field>
<field name="recurrence_interval">30</field>
<field name="otp_verification">True</field>
<field name="otp_validity_minutes">1</field>
</record>
<record id="guidance_visit" model="visits.types">
<field name="name">الارشادية</field>
<field name="creation_method">manual</field>
<field name="otp_verification">True</field>
<field name="otp_validity_minutes">5</field>
</record>
<record id="goal_visit" model="visits.types">
<field name="name">ذات هدف معين</field>
<field name="creation_method">manual</field>
</record>
</odoo>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
from . import benefit_club
from . import benefit_loans
from . import benefit_food_surplus
from . import benefit_appliances_furniture
from . import benefit_zkat_alfter
from . import benefit_food_basket
from . import payment

View File

@ -0,0 +1,285 @@
from odoo import fields, models, api
import qrcode
import base64
from io import BytesIO
class ReceiveAppliancesFurniture(models.Model):
_name = 'receive.appliances.furniture'
_inherit = ['mail.thread', 'mail.activity.mixin']
# _inherits = {'product.template': 'product_id'}
_description = 'Receive appliances and furniture need of benefit '
name = fields.Char()
donation_type = fields.Many2many('donations.type', string='')
donor_name = fields.Char()
address = fields.Char(
string='',
required=False)
lat = fields.Char(
string='',
required=False)
lon = fields.Char(
string='',
required=False)
description = fields.Char(
string='',
required=False)
phone_number = fields.Char()
product_status = fields.Many2one('item.status')
donation_method = fields.Selection(string='Donation Method', selection=[('platform', 'Platform'),
('communication', 'Communication'),
('delivery', 'Delivery'),
], required=False, )
donation_number = fields.Integer()
product_qty = fields.Integer()
image = fields.Binary(string="", )
image_1 = fields.Binary(string="", )
image_2 = fields.Binary(string="", )
image_3 = fields.Binary(string="", )
image_4 = fields.Binary(string="", )
date_receipt = fields.Date(string='Date of Receipt', required=False)
product_qty = fields.Float()
prod_id = fields.Many2one('product.product', string='Product', ondelete='cascade', copy=False, required=False)
uom_id = fields.Many2one('uom.uom')
stock_picking_id = fields.Many2one('stock.picking', string='Stock Picking', ondelete='cascade', copy=False,
required=False)
picking_type_id = fields.Many2one('stock.picking.type', string='', required=False)
state = fields.Selection([
('draft', 'Draft'),
('receipt', 'Waiting Receipt'),
('approve', 'Approved'),
('storage', 'storage'),
('refused', 'Refused'),
('done', 'Done')
], string='state', default="draft", tracking=True)
def action_submit(self):
self.state = 'receipt'
def action_done(self):
self.state = 'done'
def action_receipt(self):
self.state = 'receipt'
def action_storage(self):
customerloc, location_id = self.env['stock.warehouse']._get_partner_locations()
stock_picking = self.env['stock.picking'].create({
'picking_type_id': self.picking_type_id.id,
'location_id': location_id.id,
'location_dest_id': self.picking_type_id.default_location_dest_id.id,
})
stock_move = self.env['stock.move'].create({
'picking_id': stock_picking.id,
'product_id': self.prod_id.id,
'name': self.prod_id.name,
'product_uom_qty': self.product_qty,
'product_uom': self.prod_id.uom_id.id,
'location_id': location_id.id,
'location_dest_id': self.picking_type_id.default_location_dest_id.id,
})
self.stock_picking_id = stock_picking.id
self.state = 'storage'
def action_refused(self):
self.state = 'refused'
def action_draft(self):
self.state = 'draft'
def action_approve(self):
product = self.env['product.product'].create({
'name': self.name,
'type': 'product',
'uom_id': self.uom_id.id,
'uom_po_id': self.uom_id.id
})
self.prod_id = product
self.state = 'approve'
class AppliancesFurniture(models.Model):
_name = 'appliances.furniture'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = 'appliances and furniture need of benefit '
name = fields.Char()
benefit_id = fields.Many2one(
'grant.benefit',
string='',
required=False)
benefit_ids = fields.Many2many('grant.benefit', compute='_get_benefit')
appliances_furniture_need = fields.One2many('appliances.furniture.need', 'ap_id', tracking=True)
donation_number = fields.Integer()
delivery_date = fields.Date()
# barcode TODO
prod_id = fields.Many2one('product.product', string='Product', ondelete='cascade', copy=False, required=False)
quantity = fields.Float(compute='onchange_qty')
@api.onchange('quantity')
def onchange_qty(self):
for rec in self:
rec.quantity = 0
for i in rec.appliances_furniture_need:
rec.quantity += i.qty
qty_available = fields.Float(related='prod_id.qty_available')
stock_picking_id = fields.Many2one('stock.picking', string='Stock Picking', ondelete='cascade', copy=False,
required=False)
picking_type_id = fields.Many2one('stock.picking.type')
state = fields.Selection([
('draft', 'Draft'),
('waiting_approve', 'Waiting Approved'),
('approve', 'Approved'),
('waiting_delivery', 'Waiting delivery'),
('refused', 'Refused'),
('done', 'Done')
], string='state', default="draft", tracking=True)
def action_open_quants(self):
products = self.mapped('prod_id')
action = self.env.ref('stock.product_open_quants').read()[0]
action['domain'] = [('product_id', 'in', products.ids)]
action['context'] = {'search_default_internal_loc': 1}
return action
@api.depends('prod_id')
def _get_benefit(self):
if self.state == 'approve':
for rec in self:
rooms = rec.env['benefit.housing.rooms'].sudo().search(
[('items.item.name', '=', rec.prod_id.name)])
room_list = []
need_list = []
for room in rooms:
needs = {}
needs["ap_id"] = self.id
needs["housing_id"] = room.housing_id.id
needs["room_id"] = room.id
# needs["benefit_id"] = self.id
for test in room.items:
if test.item.name == rec.prod_id.name:
needs["status"] = test.status
needs["name"] = test.item.name
room_list.append(room.housing_id.id)
need_list.append(needs)
if rooms:
benefit = []
for room in rooms:
print(room)
benefits = rec.env['grant.benefit'].sudo().search(
[('housing_id', '=', room.housing_id.id), ('benefit_type', '=', 'benefit')])
for i in benefits:
benefit.append(i.id)
print(benefit)
# print(needs)
for r in rec:
r.benefit_ids = [(6, 0, benefit)]
# print(needs)
for ap in self.appliances_furniture_need:
for i in range(len(need_list)):
if need_list[i]['housing_id'] == ap.housing_id:
del need_list[i]
break
if not self.appliances_furniture_need:
for need_item in need_list:
test = self.sudo().write({'appliances_furniture_need': [(0, 0, need_item)]})
print(test)
def action_submit(self):
self.state = 'waiting_approve'
def action_delivery(self):
self.state = 'waiting_delivery'
def action_done(self):
self.state = 'done'
def action_draft(self):
self.state = 'draft'
def action_approve(self):
customerloc, location_id = self.env['stock.warehouse']._get_partner_locations()
stock_picking = self.env['stock.picking'].create({
'picking_type_id': self.picking_type_id.id,
'location_id': location_id.id if self.picking_type_id.code == 'incoming' else self.picking_type_id.default_location_src_id.id,
'location_dest_id': self.picking_type_id.default_location_dest_id.id if self.picking_type_id.code == 'incoming' else customerloc.id,
})
stock_move = self.env['stock.move'].create({
'picking_id': stock_picking.id,
'product_id': self.prod_id.id,
'name': self.prod_id.name,
'product_uom_qty': self.quantity,
'product_uom': self.prod_id.uom_id.id,
'location_id': location_id.id if self.picking_type_id.code == 'incoming' else self.picking_type_id.default_location_src_id.id,
'location_dest_id': self.picking_type_id.default_location_dest_id.id if self.picking_type_id.code == 'incoming' else customerloc.id,
})
self.stock_picking_id = stock_picking.id
self.state = 'approve'
class DonationsType(models.Model):
_name = 'donations.type'
_description = 'appliances and furniture need of benefits'
name = fields.Char(
string='',
required=False)
class AppliancesFurnitureNeed(models.Model):
_name = 'appliances.furniture.need'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = 'appliances and furniture needs'
name = fields.Char(
string='',
required=False)
ap_id = fields.Many2one(
'appliances.furniture',
string='',
required=False)
report_id = fields.Many2one(
'generate.reports.log',
string='',
required=False)
housing_id = fields.Many2one(
'benefit.housing',
string='',
required=False)
room_id = fields.Many2one(
'benefit.housing.rooms',
string='',
required=False)
benefit_id = fields.Many2one(
'grant.benefit',
domain="[('housing_id','=',housing_id)]",
string='',
required=False)
percentage = fields.Float()
qty = fields.Integer(
string='',
required=False)
status = fields.Many2one('item.status')
qr_code = fields.Binary("QR Code", attachment=True, store=True)
is_receive = fields.Boolean(tracking=True)
@api.onchange('housing_id', 'benefit_id', 'qr_code', 'ap_id')
def generate_qr_code(self):
if self.housing_id and self.ap_id:
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=15,
border=4,
)
name = "name:" + self.housing_id.name + " amount:" + str(self.ap_id.prod_id.name) + "date:" + str(
self.ap_id.delivery_date)
qr.add_data(name)
qr.make(fit=True)
img = qr.make_image()
temp = BytesIO()
img.save(temp, format="PNG")
qr_image = base64.b64encode(temp.getvalue())
self.qr_code = qr_image

View File

@ -0,0 +1,197 @@
from odoo import fields, models, api, _
class benefitClub(models.Model):
_name = 'benefit.club'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = 'benefit club'
name = fields.Char()
benefit_type = fields.Selection(
string='Benefit Type',
selection=[('internal', 'internal'),
('external', 'external'),
('both', 'Both'),
],
required=False, )
description = fields.Char(
string='',
required=False)
external_ids = fields.Many2many(
'external.benefits',
string='')
subscription_amount = fields.Float(
string='',
required=False)
is_available = fields.Boolean('is_available' ,default=True)
# location
# @api.multi
# def google_map_link(self, zoom=10):
#
# # params = {
# # 'q': '%s, %s %s, %s' % (self.street or '', self.city or '', self.zip or '', self.country_id and self.country_id.name_get()[0][1] or ''),
# # 'z': zoom,
# # }
# params = {
# 'q': '%s' % ('47.1922423,8.5496122'),
# 'z': zoom,
# }
# return urlplus('https://maps.google.com/maps', params)
benefit_programs = fields.Many2many(
'benefit.programs',
string='')
programs_type = fields.Selection(
string='',
selection=[('weekly', 'weekly'),
('monthly', 'Monthly'), ],
required=False, )
# program_plane = fields.Text(
# string="",
# required=False)
program_plane_ids = fields.One2many(
comodel_name='program.plane.line',
inverse_name='club_id',
string='',
required=False)
benefit_ids = fields.Many2many(
'grant.benefit',
string='Benefit',
required=False)
state = fields.Selection([
('draft', 'Draft'),
('waiting_approve', 'Waiting Approved'),
('approve', 'Approved'),
('refused', 'Refused'),
('done', 'Done')
], string='state', default="draft", tracking=True)
requests_total = fields.Integer(string="Requests Total", compute="get_total")
def action_submit(self):
self.state = 'waiting_approve'
def action_approve(self):
self.state = 'approve'
def action_refused(self):
self.state = 'refused'
def action_done(self):
self.state = 'done'
def get_total(self):
for request in self:
if request.id:
requests = request.env['external.request'].sudo().search(
[('club_id', '=', request.id), ('state', '=', 'draft')])
self.requests_total = len(requests)
def open_external_request(self):
context = {}
context['default_club_id'] = self.id
return {
'name': _('External Request'),
'view_type': 'form',
'view_mode': 'tree,form',
'views': [(self.env.ref(
'odex_benefit.external_request_tree').id, 'tree'),
(self.env.ref('odex_benefit.external_request_form').id, 'form')],
'res_model': 'external.request',
'type': 'ir.actions.act_window',
'context': context,
'domain': "[('club_id','=',%s)]" % (self.id),
'target': 'current',
}
class ProgramPlane(models.Model):
_name = 'program.plane.line'
_description = 'Benefit Programs'
club_id = fields.Many2one('benefit.club')
benefit_ids = fields.Many2many('grant.benefit', related='club_id.benefit_ids',
string='Benefit',
required=False)
date_from = fields.Date(
string='',
required=False)
date_to = fields.Date(
string='',
required=False)
activity_type = fields.Many2one(
comodel_name='benefit.club.activity',
string='',
required=False)
description = fields.Char()
attendees = fields.Many2many('grant.benefit', domain="[('id','in',benefit_ids)]", )
score = fields.Float(
string='',
required=False)
class ProgramActivity(models.Model):
_name = 'benefit.club.activity'
_description = 'Benefit Programs'
name = fields.Char()
description = fields.Char()
class BenefitPrograms(models.Model):
_name = 'benefit.programs'
_description = 'Benefit Programs'
name = fields.Char()
description = fields.Char()
behaviors_programs = fields.Many2many(
'benefit.behaviors.type',
string='')
class ExternalRequest(models.Model):
_name = 'external.request'
_rec_name = 'external_id'
_description = 'External Request'
club_id = fields.Many2one(
comodel_name='benefit.club',
string='',
required=False)
zkat_id = fields.Many2one(
comodel_name='benefit.zkat',
string='',
required=False)
external_id = fields.Many2one(
'external.benefits',
string='External Benefit')
country_id = fields.Many2one('res.country', related='external_id.country_id', string='Country')
state_id = fields.Many2one('res.country.state', related='external_id.state_id', string='Country State')
city_id = fields.Many2one('res.country.city', related='external_id.city_id', string='City')
street = fields.Char(string='District', related='external_id.street')
location = fields.Char(string='location', related='external_id.location')
lat = fields.Char()
lon = fields.Char()
state = fields.Selection([
('draft', 'Draft'),
('approve', 'Approved'),
('refused', 'Refused'),
], string='state', default="draft", tracking=True)
def action_accept(self):
self.state = 'approve'
if self.club_id:
for id in self.club_id:
id.write({'external_ids': [(4, self.external_id.id)]})
if self.zkat_id:
for id in self.zkat_id:
id.write({'external_ids': [(4, self.external_id.id)]})
def action_refused(self):
self.state = 'refused'

View File

@ -0,0 +1,373 @@
import base64
from io import BytesIO
from random import randint
import qrcode
from odoo import models, fields, api, _
from datetime import datetime, date, timedelta
from odoo.exceptions import UserError, ValidationError
# receive
class ReceiveFoodBasket(models.Model):
_name = 'receive.food.basket'
_description = 'receive food basket'
_inherit = ['mail.thread', 'mail.activity.mixin']
# TODO
# barcode
# sms notification
name = fields.Char()
date_start = fields.Date(
string='',
required=False)
date_end = fields.Date(
string='',
required=False)
donation_method = fields.Selection(
string='Donation Method',
selection=[('inside', 'inside the assembly'),
('outside', 'outside the assembly'),
('both', 'Both'),
],
required=False, )
donation_type = fields.Selection(
string='',
selection=[('material', 'Material'),
('cash', 'cash'),
('both', 'Both'),
],
required=False, )
amount = fields.Float(string="Amount", compute='_compute_amount_quantity')
quantity = fields.Float(compute='_compute_amount_quantity', string='Quantity',
required=False)
# Payment
code = fields.Char(string="Code", copy=False, readonly=True, default=lambda x: _('New'))
journal_id = fields.Many2one('account.journal')
account_id = fields.Many2one('account.account', )
entry_id = fields.Many2one('account.move', string="Entry")
product_id = fields.Many2one('product.product', string='Product', ondelete='cascade', copy=False, required=False)
qty_available = fields.Float(related='product_id.qty_available')
stock_picking_id = fields.Many2one('stock.picking', string='Stock Picking', ondelete='cascade', copy=False,
required=False)
picking_type_id = fields.Many2one('stock.picking.type', string='', required=False)
purchase_order_id = fields.Many2one('purchase.order', string='Order Reference', index=True,
ondelete='cascade')
description = fields.Char(
string='',
required=False)
# donation_type = cash
donation_amount = fields.Float(
compute='_get_total_donation',
string='',
required=False)
amount_ids = fields.One2many(
'food.basket.line',
inverse_name='food_basket_id',
string='',
required=False)
donation_type = fields.Many2many('donations.type',
string='')
delivery_date = fields.Date(
string='Delivery Date',
required=False)
@api.onchange('amount_ids')
def _compute_amount_quantity(self):
for rec in self:
rec.amount = 0.0
rec.quantity = 0.0
if rec.amount_ids:
for payment in rec.amount_ids:
rec.amount += payment.amount
rec.quantity += payment.qty
def _get_total_donation(self):
total_donation = 0.0
for i in self.amount_ids:
total_donation += i.amount
self.donation_amount = total_donation
# barcode
state = fields.Selection([
('draft', 'Draft'),
('approve', 'Approved'),
('receiving', ' Receiving'),
('piking', 'Piking'),
('done', 'Done'),
('refused', 'Refused'),
('cancel', 'Cancel'),
], string='state', default="draft", tracking=True)
def action_open_quants(self):
products = self.mapped('product_id')
action = self.env.ref('stock.product_open_quants').read()[0]
action['domain'] = [('product_id', 'in', products.ids)]
action['context'] = {'search_default_internal_loc': 1}
return action
def action_submit(self):
self.state = 'submit'
def action_approve(self):
self.state = 'approve'
def action_receiving(self):
self.state = 'receiving'
def action_restriction(self):
self.state = 'restriction'
def action_done(self):
self.state = 'done'
def action_cancel(self):
self.state = 'cancel'
def action_compute(self):
print(self.amount < 0)
print(self.purchase_order_id.id)
if (self.amount < 0 and not self.purchase_order_id.id) or self.amount == 0:
raise ValidationError(_(u' No pay'))
customerloc, location_id = self.env['stock.warehouse']._get_partner_locations()
stock_picking = self.env['stock.picking'].create({
'picking_type_id': self.picking_type_id.id,
'location_id': location_id.id,
# 'product_uom_qty': self.quantity,
'location_dest_id': self.picking_type_id.default_location_dest_id.id,
})
stock_move = self.env['stock.move'].create({
'picking_id': stock_picking.id,
'product_id': self.product_id.id,
'name': self.product_id.name,
'product_uom_qty': self.quantity,
'product_uom': self.product_id.uom_id.id,
'location_id': location_id.id,
'location_dest_id': self.picking_type_id.default_location_dest_id.id,
})
self.stock_picking_id = stock_picking.id
self.state = 'piking'
def action_compute_purchase_order(self):
move_id = self.env['account.move'].sudo().create({
'journal_id': self.journal_id.id,
'ref': self.code})
move_line = []
move_line.append({
'debit': self.amount,
'credit': 0.0,
'account_id': self.account_id.id,
})
move_line.append({
'debit': 0.0,
'credit': self.amount,
'account_id': self.account_id.id,
})
move_id.write({'line_ids': [(0, 0, line) for line in move_line]})
move_id.post()
self.entry_id = move_id.id
po = self.env['purchase.order'].create({
'partner_id':self.amount_ids.donor_parnter.id,
'date_planned': date.today(),
'state': 'draft',
})
pol = self.env['purchase.order.line'].create({
'order_id': po.id,
'product_id': self.product_id.id,
'name': self.product_id.name,
'product_qty': self.amount / self.product_id.standard_price,
'date_planned': date.today(),
'product_uom': self.product_id.uom_id.id,
'price_unit': self.product_id.standard_price,
})
self.purchase_order_id = po.id
class RFoodBasket(models.Model):
_name = 'food.basket.line'
_description = 'food basket'
food_basket_id = fields.Many2one(
'receive.food.basket',
string='',
required=False)
name = fields.Char(
string='Donor name',
required=False)
def _get_default_color(self):
return randint(1, 11)
color = fields.Integer(string='Color Index', default=_get_default_color)
donation_method = fields.Selection(
string='Donation Method',
selection=[('inside', 'inside the assembly'),
('outside', 'outside the assembly'),
],
required=False, )
donor_partner = fields.Many2one('res.partner')
phone_number = fields.Char()
donation_type = fields.Selection(
string='',
selection=[('material', 'Material'),
('cash', 'cash'),
('both', 'Both'),
],
required=False, )
payment_id = fields.Many2one('account.payment')
currency_id = fields.Many2one('res.currency', string='Currency', related='payment_id.currency_id', readonly=True)
# amount = fields.Monetary(
# related='payment_id.amount',
# string='Amount',
# required=False)
amount = fields.Monetary(string='Amount',
required=False)
qty = fields.Float(
string='',
required=False)
##########################################################################
class benefitFoodBasket(models.Model):
_name = 'benefit.food.basket'
_description = 'benefit food basket'
_inherit = ['mail.thread', 'mail.activity.mixin']
# TODO
# barcode
# sms notification
name = fields.Char()
date_start = fields.Date(
string='',
required=False)
date_end = fields.Date(
string='',
required=False)
# donation_type = cash
donation_amount = fields.Float(
string='',
required=False)
donation_type = fields.Many2many('donations.type',
string='')
benefit_ids = fields.One2many(
'food.basket.benefits.line',
'food_basket_id',
string='')
delivery_date = fields.Date(
string='Delivery Date',
required=False)
product_id = fields.Many2one('product.product', string='Product', ondelete='cascade', copy=False, required=False)
qty_available = fields.Float(related='product_id.qty_available')
quantity = fields.Float(
compute='onchange_quantity',
string='Quantity',
required=False)
stock_picking_id = fields.Many2one('stock.picking', string='Stock Picking', ondelete='cascade', copy=False,
required=False)
picking_type_id = fields.Many2one('stock.picking.type')
state = fields.Selection([
('draft', 'Draft'),
('waiting_approve', 'Waiting Approved'),
('approve', 'Approved'),
('calculation', 'calculation'),
('waiting_delivery', 'Waiting delivery'),
('refused', 'Refused'),
('done', 'Done')
], string='state', default="draft", tracking=True)
def action_open_quants(self):
products = self.mapped('product_id')
action = self.env.ref('stock.product_open_quants').read()[0]
action['domain'] = [('product_id', 'in', products.ids)]
action['context'] = {'search_default_internal_loc': 1}
return action
@api.onchange('benefit_ids')
def onchange_quantity(self):
for rec in self.benefit_ids:
self.quantity += rec.qty
self.quantity = 0
def action_submit(self):
self.state = 'waiting_approve'
def action_approve(self):
self.state = 'approve'
def action_calculation(self):
self.action_compute()
self.state = 'calculation'
def action_compute(self):
customerloc, location_id = self.env['stock.warehouse']._get_partner_locations()
stock_picking = self.env['stock.picking'].create({
'picking_type_id': self.picking_type_id.id,
'location_id': location_id.id if self.picking_type_id.code == 'incoming' else self.picking_type_id.default_location_src_id.id,
# 'product_uom_qty': self.quantity,
'location_dest_id': self.picking_type_id.default_location_dest_id.id if self.picking_type_id.code == 'incoming' else customerloc.id,
})
stock_move = self.env['stock.move'].create({
'picking_id': stock_picking.id,
'product_id': self.product_id.id,
'name': self.product_id.name,
'product_uom_qty': self.quantity,
'product_uom': self.product_id.uom_id.id,
'location_id': location_id.id if self.picking_type_id.code == 'incoming' else self.picking_type_id.default_location_src_id.id,
'location_dest_id': self.picking_type_id.default_location_dest_id.id if self.picking_type_id.code == 'incoming' else customerloc.id,
})
self.stock_picking_id = stock_picking.id
def action_refused(self):
self.state = 'refused'
def action_delivery(self):
self.state = 'waiting_delivery'
def action_done(self):
self.state = 'done'
class FoodBasketBenefits(models.Model):
_name = 'food.basket.benefits.line'
_description = 'food basket'
food_basket_id = fields.Many2one(
'benefit.food.basket',
string='food Basket id',
required=False)
family_id = fields.Many2one('benefit.family', string='Benefit Family')
family_member = fields.Integer(related='family_id.benefits_total')
qty = fields.Float(
string='',
required=False)
date = fields.Datetime(
string='',
required=False)
qr_code = fields.Binary("QR Code", attachment=True, store=True)
is_receive = fields.Boolean(
string='',
required=False)
@api.onchange('family_id', 'qr_code', 'date')
def generate_qr_code(self):
if self.family_id and self.qty and self.date:
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=15,
border=4,
)
name = "name:" + self.family_id.name + " amount:" + str(self.qty) + "date:" + str(self.date)
qr.add_data(name)
qr.make(fit=True)
img = qr.make_image()
temp = BytesIO()
img.save(temp, format="PNG")
qr_image = base64.b64encode(temp.getvalue())
self.qr_code = qr_image

View File

@ -0,0 +1,243 @@
from odoo import fields, models, api, _
from datetime import datetime
from odoo.exceptions import UserError, ValidationError
# receive
class ReceiveFoodSurplus(models.Model):
_name = 'receive.food.surplus'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = 'Receive Food Surplus'
# TODO
# barcode
# sms notification
name = fields.Char()
surplus_type = fields.Many2many(
'food.surplus.type',
string='',
required=False)
quantity = fields.Float(
compute='_compute_quantity',
string='',
required=False)
zone = fields.Char(
string='',
required=False)
neighborhood = fields.Char(
string='',
required=False)
city_id = fields.Many2one(
comodel_name='res.country.city',
string='',
required=False)
address = fields.Char(
string='',
required=False)
location = fields.Char(
string='Location',
required=False)
surplus_ids = fields.One2many(
'food.surplus.line',
'food_surplus_id',
string='surplus',
required=False)
# barcode
state = fields.Selection([
('draft', 'Draft'),
('waiting_approve', 'Waiting Approved'),
('approve', 'Approved'),
('refused', 'Refused')
], string='state', default="draft", tracking=True)
# @api.multi
def open_map(self):
for Location in self:
url = "http://maps.google.com/maps?oi=map&q="
if Location.city_id:
url += '+' + Location.city_id.name.replace(' ', '+')
url += '+' + Location.city_id.state_id.name.replace(' ', '+')
url += '+' + Location.city_id.country_id.name.replace(' ', '+')
if Location.zone:
url += '+' + Location.zone.replace(' ', '+')
if Location.name:
url += Location.name.replace(' ', '+')
return {
'type': 'ir.actions.act_url',
'target': 'new',
'url': url
}
def action_submit(self):
self.state = 'waiting_approve'
def action_approve(self):
self.state = 'approve'
def action_refused(self):
self.state = 'refused'
@api.onchange('surplus_ids')
def _compute_quantity(self):
for rec in self:
rec.quantity = 0.0
if rec.surplus_ids:
for payment in rec.surplus_ids:
rec.quantity += payment.quantity
class benefitFoodSurplus(models.Model):
_name = 'benefit.food.surplus'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = 'Food Surplus'
# TODO
# barcode
# sms notification
partner_id = fields.Many2one('res.partner', 'Responsible')
name = fields.Char()
surplus_type = fields.Many2many(
'food.surplus.type',
string='',
required=False)
benefit_count = fields.Integer(
string='',
required=False)
phone = fields.Char(related='partner_id.phone')
quantity = fields.Float(
compute='_compute_quantity',
string='',
required=False)
zone = fields.Char(
string='',
required=False)
neighborhood = fields.Char(
string='',
required=False)
city_id = fields.Many2one(
comodel_name='res.country.city',
string='',
required=False)
address = fields.Char(
string='',
required=False)
location = fields.Char(
string='Location',
required=False)
lat = fields.Char()
lon = fields.Char()
surplus_ids = fields.One2many(
'food.surplus.line',
'food_surplus_id',
string='surplus',
required=False)
# barcode
state = fields.Selection([
('draft', 'Draft'),
('waiting_approve', 'Waiting Approved'),
('approve', 'Approved'),
('refused', 'Refused')
], string='state', default="draft", tracking=True)
# @api.multi
def open_map(self):
for Location in self:
url = "http://maps.google.com/maps?oi=map&q="
if Location.city_id:
url += '+' + Location.city_id.name.replace(' ', '+')
url += '+' + Location.city_id.state_id.name.replace(' ', '+')
url += '+' + Location.city_id.country_id.name.replace(' ', '+')
if Location.zone:
url += '+' + Location.zone.replace(' ', '+')
if Location.name:
url += Location.name.replace(' ', '+')
return {
'type': 'ir.actions.act_url',
'target': 'new',
'url': url
}
def action_submit(self):
self.state = 'waiting_approve'
def action_approve(self):
self.state = 'approve'
def action_refused(self):
self.state = 'refused'
@api.onchange('surplus_ids')
def _compute_quantity(self):
for rec in self:
rec.quantity = 0.0
if rec.surplus_ids:
for payment in rec.surplus_ids:
rec.quantity += payment.quantity
class FoodSurplus(models.Model):
_name = 'food.surplus.line'
_description = 'Food Surplus'
food_surplus_id = fields.Many2one(
'benefit.food.surplus',
string='',
required=False)
benefit_ids = fields.Many2many(
'grant.benefit',
string='',
required=False)
surplus_type = fields.Many2one(
'food.surplus.type',
string='',
required=False)
surplus_count = fields.Integer(
string='',
required=False)
date_start = fields.Date(
string='',
required=False)
date_end = fields.Date(
string='',
required=False)
quantity = fields.Float(
string='',
required=False)
description = fields.Char(
string='',
required=False)
is_available = fields.Boolean(compute="_compute_available", store=True)
@api.onchange('benefit_ids')
def _compute_available(self):
for rec in self:
now = datetime.now().date()
if rec.date_start and rec.date_end:
if len(rec.benefit_ids) > rec.surplus_count or (str(rec.date_start) <= str(now) <= str(rec.date_end)):
rec.is_available = True
else:
rec.is_available = False
@api.onchange('benefit_ids')
def benefit_limit(self):
for rec in self:
if len(rec.benefit_ids) <= rec.surplus_count:
pass
else:
raise ValidationError(
_(u' You cant Add benefits'))
class FoodSurplusType(models.Model):
_name = 'food.surplus.type'
_description = 'Food Surplus'
name = fields.Char(
string='',
required=False)
description = fields.Char(
string='description',
required=False)

View File

@ -0,0 +1,214 @@
import datetime
from odoo import fields, models, api, _
from odoo.exceptions import UserError, ValidationError
class benefitLoans(models.Model):
_name = 'receive.benefit.loans'
_description = 'benefit Loans'
_inherit = ['mail.thread', 'mail.activity.mixin']
name = fields.Char()
donation_type = fields.Many2many('donations.type',
string='')
number_of_installments = fields.Integer(
string='Number of installments',
required=False)
installment_value = fields.Float(
string='Installment Value',
compute="_get_installment_value",
required=False)
receive_date = fields.Date(
string='Receive Date',
required=False)
account_payment_id = fields.Many2one('account.payment')
loan_amount = fields.Monetary(
related='account_payment_id.amount',
string='Loan Amount',
required=False)
currency_id = fields.Many2one('res.currency', string='Currency', required=True,
default=lambda self: self.env.user.company_id.currency_id)
state = fields.Selection([
('draft', 'Draft'),
('announced', 'announced'),
('booked_up', 'booked up'),
('approve', 'Approved'),
('refused', 'Refused'),
('done', 'Done')
], string='state', default="draft", tracking=True)
def action_submit(self):
self.state = 'announced'
def action_booked_up(self):
self.state = 'booked_up'
def action_approve(self):
self.state = 'approve'
def action_refused(self):
self.state = 'refused'
def action_done(self):
self.state = 'done'
@api.onchange('loan_amount', 'number_of_installments')
def _get_installment_value(self):
self.installment_value = 0.0
if self.number_of_installments > 0:
self.installment_value = (self.loan_amount / self.number_of_installments)
class benefitLoans(models.Model):
_name = 'benefit.loans'
_description = 'benefit Loans'
_inherit = ['mail.thread', 'mail.activity.mixin']
name = fields.Char()
family_id = fields.Many2one('benefit.family')
responsible_id = fields.Many2one('grant.benefit', related='family_id.responsible_benefit_id',
string='responsible',
required=False)
benefits_total = fields.Integer(string="Benefit Total", related="family_id.benefits_total")
description = fields.Char()
donation_type = fields.Many2many('donations.type', string='')
loan_amount = fields.Float(
string='Loan Amount',
required=False)
number_of_installments = fields.Integer(
string='Number of installments',
required=False)
account_payment_id = fields.Many2one('account.payment')
journal_id = fields.Many2one('account.journal')
installment_value = fields.Float(
string='Installment Value',
compute="_get_installment_value",
required=False)
purchase_product_ids = fields.One2many('purchase.product.loan', 'loan_id')
purchase_order_id = fields.Many2one('purchase.order', string='Order Reference', index=True,
ondelete='cascade')
payment_method_id = fields.Many2one('account.payment.method', string='Payment Type', required=True)
currency_id = fields.Many2one('res.currency', string='Currency', required=True,
default=lambda self: self.env.user.company_id.currency_id)
stock_picking_id = fields.Many2one('stock.picking', string='Stock Picking', ondelete='cascade', copy=False,
required=False)
picking_type_id = fields.Many2one('stock.picking.type')
delivery_date = fields.Date(string='Delivery Date', required=False)
state = fields.Selection([
('draft', 'Draft'),
('announced', 'announced'),
('booked_up', 'booked up'),
('approve', 'Approved'),
('refused', 'Refused'),
('done', 'Done')
], string='state', default="draft", tracking=True)
@api.onchange('purchase_product_ids')
def _onchange_product_ids(self):
for rec in self:
if rec.id:
products_total = 0.0
for product in rec.purchase_product_ids:
products_total += product.price
if products_total >= self.loan_amount:
print(self.loan_amount)
print(products_total)
raise ValidationError(_(u'The specified quantities exceed the specified price of the loan'))
def action_purchase(self):
po = self.env['purchase.order'].create({
'partner_id': self.responsible_id.partner_id.id, # todo
'date_planned': datetime.date.today(),
'state': 'draft',
})
for product in self.purchase_product_ids:
pol = self.env['purchase.order.line'].create({
'order_id': po.id,
'product_id': product.product_id.id,
'name': product.product_id.name,
'product_qty': product.quantity,
'date_planned': datetime.date.today(),
'product_uom': product.product_id.uom_id.id,
'price_unit': product.product_id.list_price,
})
self.purchase_order_id = po.id
def action_compute(self):
customerloc, location_id = self.env['stock.warehouse']._get_partner_locations()
stock_picking = self.env['stock.picking'].create({
'picking_type_id': self.picking_type_id.id,
'location_id': location_id.id if self.picking_type_id.code == 'incoming' else self.picking_type_id.default_location_src_id.id,
# 'product_uom_qty': self.quantity,
'location_dest_id': self.picking_type_id.default_location_dest_id.id if self.picking_type_id.code == 'incoming' else customerloc.id,
})
for product in self.purchase_product_ids:
stock_move = self.env['stock.move'].create({
'picking_id': stock_picking.id,
'product_id': product.product_id.id,
'name': product.product_id.name,
'product_uom_qty': product.quantity,
'product_uom': product.product_id.uom_id.id,
'location_id': location_id.id if self.picking_type_id.code == 'incoming' else self.picking_type_id.default_location_src_id.id,
'location_dest_id': self.picking_type_id.default_location_dest_id.id if self.picking_type_id.code == 'incoming' else customerloc.id,
})
self.stock_picking_id = stock_picking.id
def action_submit(self):
self.state = 'announced'
def action_booked_up(self):
self.state = 'booked_up'
def action_draft(self):
self.state = 'draft'
def action_approve(self):
# self.action_compute()
self.action_purchase()
account_payment = self.env['account.payment'].create({
'name': '/',
'partner_type': 'customer',
'partner_id': self.responsible_id.partner_id.id,
'payment_type': 'outbound',
'journal_id': self.journal_id.id,
'payment_method_id': self.payment_method_id.id,
'currency_id': self.currency_id.id,
'amount': self.loan_amount,
# 'payment_date': datetime.datetime.now(),
'benefit_loan_id': self.id,
})
self.account_payment_id = account_payment
self.state = 'approve'
def action_refused(self):
self.state = 'refused'
def action_done(self):
self.state = 'done'
@api.onchange('loan_amount', 'number_of_installments')
def _get_installment_value(self):
self.installment_value = 0.0
if self.number_of_installments > 0:
self.installment_value = (self.loan_amount / self.number_of_installments)
class purchaseProductLoan(models.Model):
_name = 'purchase.product.loan'
_description = 'Purchase Benefit Loans'
loan_id = fields.Many2one('benefit.loans')
product_id = fields.Many2one('product.product')
list_price = fields.Float(
related='product_id.list_price',
string='',
required=False)
quantity = fields.Float()
price = fields.Float(compute='_compute_price')
@api.onchange('quantity')
def _compute_price(self):
for rec in self:
rec.price = rec.list_price * rec.quantity

View File

@ -0,0 +1,498 @@
from odoo import models, fields, api, _
from datetime import datetime, date, timedelta
from odoo.exceptions import UserError, ValidationError
# receiving zakat
class ReceiveZkat(models.Model):
_name = 'receive.benefit.zkat'
_description = 'receive of zkat al-feter of benefit'
_inherit = ['mail.thread', 'mail.activity.mixin']
name = fields.Char(string="Name")
description = fields.Char(string="Name")
code = fields.Char(string="Code", copy=False, readonly=True, default=lambda x: _('New'))
journal_id = fields.Many2one('account.journal')
account_id = fields.Many2one('account.account', )
date_from = fields.Date(string="Date start")
date_to = fields.Date(string="Date end")
entry_id = fields.Many2one('account.move', string="Entry")
# Payment collection
payment_collection_ids = fields.One2many('payment.collection.line', 'receive_zkat_id')
donation_method = fields.Selection(
string='Donation Method',
selection=[('inside', 'inside the assembly'),
('outside', 'outside the assembly'), ], required=False, )
uint = fields.Float()
uint_price = fields.Float()
amount = fields.Float(string="Amount", compute='_compute_amount_quantity')
quantity = fields.Float(compute='_compute_amount_quantity', string='Quantity',
required=False)
purchase_order_id = fields.Many2one('purchase.order', string='Order Reference', index=True,
ondelete='cascade')
product_id = fields.Many2one('product.product', string='Product', ondelete='cascade', copy=False, required=False)
qty_available = fields.Float(related='product_id.qty_available')
stock_picking_id = fields.Many2one('stock.picking', string='Stock Picking', ondelete='cascade', copy=False,
required=False)
picking_type_id = fields.Many2one('stock.picking.type', string='', required=False)
state = fields.Selection([
('draft', 'Draft'),
('approve', 'Approved'),
('receiving', ' Receiving'),
('piking', 'Piking'),
('done', 'Done'),
('refused', 'Refused'),
('cancel', 'Cancel'),
], string='state', default="draft", tracking=True)
@api.model
def create(self, vals):
res = super(ReceiveZkat, self).create(vals)
if not res.code or res.code == _('New'):
res.code = self.env['ir.sequence'].sudo().next_by_code('benefit.receive.zkat.sequence') or _('New')
return res
def action_open_quants(self):
products = self.mapped('product_id')
action = self.env.ref('stock.product_open_quants').read()[0]
action['domain'] = [('product_id', 'in', products.ids)]
action['context'] = {'search_default_internal_loc': 1}
return action
def action_compute(self):
if (self.amount < 0 and not self.purchase_order_id.id) or self.amount == 0:
raise ValidationError(_(u' No pay'))
customerloc, location_id = self.env['stock.warehouse']._get_partner_locations()
stock_picking = self.env['stock.picking'].create({
'picking_type_id': self.picking_type_id.id,
'location_id': location_id.id,
# 'product_uom_qty': self.quantity,
'location_dest_id': self.picking_type_id.default_location_dest_id.id,
})
stock_move = self.env['stock.move'].create({
'picking_id': stock_picking.id,
'product_id': self.product_id.id,
'name': self.product_id.name,
'product_uom_qty': self.quantity,
'product_uom': self.product_id.uom_id.id,
'location_id': location_id.id,
'location_dest_id': self.picking_type_id.default_location_dest_id.id,
})
self.stock_picking_id = stock_picking.id
self.state = 'piking'
def action_compute_purchase_order(self):
move_id = self.env['account.move'].sudo().create({
'journal_id': self.journal_id.id,
'ref': self.code})
move_line = []
move_line.append({
'debit': self.amount,
'credit': 0.0,
'account_id': self.account_id.id,
})
move_line.append({
'debit': 0.0,
'credit': self.amount,
'account_id': self.account_id.id,
})
move_id.write({'line_ids': [(0, 0, line) for line in move_line]})
move_id.post()
self.entry_id = move_id.id
po = self.env['purchase.order'].create({
'partner_id': self.payment_collection_ids.donor_partner.id,
'date_planned': date.today(),
'state': 'draft',
})
pol = self.env['purchase.order.line'].create({
'order_id': po.id,
'product_id': self.product_id.id,
'name': self.product_id.name,
'product_qty': self.amount / self.product_id.standard_price if self.product_id.standard_price > 0 else 0 ,
'date_planned': date.today(),
'product_uom': self.product_id.uom_id.id,
'price_unit': self.product_id.standard_price,
})
self.purchase_order_id = po.id
def action_approve(self):
self.state = 'approve'
def action_draft(self):
self.state = 'draft'
self.purchase_order_id.unlink()
@api.onchange('payment_collection_ids')
def _compute_amount_quantity(self):
for rec in self:
rec.amount = 0.0
rec.quantity = 0.0
if rec.payment_collection_ids:
for payment in rec.payment_collection_ids:
rec.amount += payment.amount
rec.quantity += payment.quantity
def action_refuse(self):
self.state = 'refused'
def action_receiving(self):
self.state = 'receiving'
def action_submit(self):
self.state = 'submit'
def action_restriction(self):
self.state = 'restriction'
# def action_paid(self):
# self.state = 'paid'
def action_done(self):
self.state = 'done'
def action_cancel(self):
self.state = 'cancel'
def create_entry(self):
move_id = self.env['account.move'].sudo().create({
'journal_id': self.company_id.benefit_journal_id.id,
'ref': self.code})
move_line = []
move_line.append({
'debit': self.amount,
'credit': 0.0,
'account_id': self.company_id.benefit_account_id.id,
})
move_line.append({
'debit': 0.0,
'credit': self.amount,
'account_id': self.company_id.benefit_bank_account_id.id,
})
move_id.write({'line_ids': [(0, 0, line) for line in move_line]})
move_id.post()
self.entry_id = move_id.id
class zkat(models.Model):
_name = 'benefit.zkat'
_description = 'percentage of zkat al-feter of benefit '
_inherit = ['mail.thread', 'mail.activity.mixin']
name = fields.Char(string="Name")
code = fields.Char(string="Code", copy=False, readonly=True, default=lambda x: _('New'))
journal_id = fields.Many2one('account.journal')
account_id = fields.Many2one('account.account', )
date_from = fields.Date(string="Date start")
date_to = fields.Date(string="Date end")
delivery_date = fields.Date(
string='Delivery Date',
required=False)
donation_method = fields.Selection(
string='Donation Method',
selection=[('inside', 'inside the assembly'),
('outside', 'outside the assembly'),
],
required=False, )
uint = fields.Float(
string='',
required=False)
uint_amount = fields.Float(
string='',
required=False)
product_id = fields.Many2one('product.product', string='Product', ondelete='cascade', copy=False, required=False)
qty_available = fields.Float(related='product_id.qty_available')
quantity = fields.Float(
compute='onchange_quantity',
string='Quantity',
required=False)
benefit_ids = fields.Many2many(
'grant.benefit',
string='')
zkat_ids = fields.One2many(
comodel_name='zkat.line',
inverse_name='zkat_id',
string='',
required=False)
external_ids = fields.Many2many(
'external.benefits',
string='External Benefits')
user_id = fields.Many2one('res.users', string="User", default=lambda self: self.env.user)
company_id = fields.Many2one('res.company', string="Company", default=lambda self: self.env.user.company_id)
parent_id = fields.Many2one('benefit.zkat', string="Parent")
line_ids = fields.One2many('benefit.zkat.line', 'year_id', string="Lines")
is_appendix = fields.Boolean(
string='is appendix',
required=False)
housing_id = fields.Many2one(
'benefit.housing',
string='',
required=False)
state = fields.Selection([
('draft', 'Draft'),
('restriction', 'restriction'),
('approve', 'Approved'),
('piking', 'Piking'),
('delivery', 'Delivery'),
('done', 'Done'),
('refused', 'Refused'),
('cancel', 'Cancel'),
], string='state', default="draft", tracking=True)
entry_id = fields.Many2one('account.move', string="Entry")
is_benefits = fields.Boolean(
string='is benefits',
required=False)
requests_total = fields.Integer(string="Requests Total", compute="get_total")
stock_picking_id = fields.Many2one('stock.picking', string='Stock Picking', ondelete='cascade', copy=False,
required=False)
picking_type_id = fields.Many2one('stock.picking.type')
def action_compute(self):
customerloc, location_id = self.env['stock.warehouse']._get_partner_locations()
stock_picking = self.env['stock.picking'].create({
'picking_type_id': self.picking_type_id.id,
'location_id': location_id.id if self.picking_type_id.code == 'incoming' else self.picking_type_id.default_location_src_id.id,
# 'product_uom_qty': self.quantity,
'location_dest_id': self.picking_type_id.default_location_dest_id.id if self.picking_type_id.code == 'incoming' else customerloc.id,
})
stock_move = self.env['stock.move'].create({
'picking_id': stock_picking.id,
'product_id': self.product_id.id,
'name': self.product_id.name,
'product_uom_qty': self.quantity,
'product_uom': self.product_id.uom_id.id,
'location_id': location_id.id if self.picking_type_id.code == 'incoming' else self.picking_type_id.default_location_src_id.id,
'location_dest_id': self.picking_type_id.default_location_dest_id.id if self.picking_type_id.code == 'incoming' else customerloc.id,
})
self.stock_picking_id = stock_picking.id
self.state = 'piking'
def action_open_quants(self):
products = self.mapped('product_id')
action = self.env.ref('stock.product_open_quants').read()[0]
action['domain'] = [('product_id', 'in', products.ids)]
action['context'] = {'search_default_internal_loc': 1}
return action
@api.onchange('zkat_ids')
def onchange_quantity(self):
for rec in self.zkat_ids:
self.quantity += rec.net
self.quantity = 0
def action_draft(self):
for rec in self:
rec.state = 'draft'
@api.onchange('zkat_ids')
def compute_uint_amount(self):
if self.state in ['draft', 'restriction']:
quantity = 0.0
for rec in self.zkat_ids:
quantity += rec.quantity
try:
uint_amount = (self.qty_available / quantity) * 100
self.uint_amount = 100 if uint_amount > 100 else uint_amount
except:
pass
def get_total(self):
for request in self:
if request.id:
requests = request.env['external.request'].sudo().search(
[('zkat_id', '=', request.id), ('state', '=', 'draft')])
self.requests_total = len(requests)
def open_external_request(self):
context = {}
context['default_zkat_id'] = self.id
return {
'name': _('External Request'),
'view_type': 'form',
'view_mode': 'tree,form',
'views': [(self.env.ref(
'odex_benefit.external_request_tree').id, 'tree'),
(self.env.ref('odex_benefit.external_request_form').id, 'form')],
'res_model': 'external.request',
'type': 'ir.actions.act_window',
'context': context,
'domain': "[('zkat_id','=',%s)]" % (self.id),
'target': 'current',
}
@api.model
def create(self, vals):
res = super(zkat, self).create(vals)
if not res.code or res.code == _('New'):
res.code = self.env['ir.sequence'].sudo().next_by_code('benefit.zkat.sequence') or _('New')
return res
@api.model
def payment_cron(self):
payment = self.env['benefit.zkat'].search([('state', '=', 'approve'), ('date', '=', str(datetime.now().date())),
('line_ids', '=', False)], limit=1)
if payment:
payment.action_create_lines()
def open_payments(self):
return {
'name': "Payments",
'view_type': 'form',
'view_mode': 'tree,form',
'views': [(self.env.ref(
'odex_benefit.benefit_year_payment_line_tree').id, 'tree'),
(self.env.ref('odex_benefit.benefit_year_payment_line_form').id, 'form')],
'res_model': 'benefit.zkat.line',
'type': 'ir.actions.act_window',
'domain': "[('year_id','=',%s)]" % (self.id),
'target': 'current',
}
def compute_benefit(self):
benefits = self.env['grant.benefit'].sudo().search([]).mapped('family_id')
for rec in benefits:
self.env['zkat.line'].create({
'zkat_id': self.id,
'family_id': rec.id,
})
def action_approve(self):
self.state = 'approve'
def action_pay(self):
if self.is_benefits == True:
self.sudo().create_entry()
self.state = 'paid'
else:
raise ValidationError(
_(u' No benefits for pay'))
def action_refuse(self):
self.state = 'refused'
def action_receiving(self):
self.state = 'receiving'
def action_submit(self):
self.state = 'submit'
def action_restriction(self):
self.compute_benefit()
self.compute_uint_amount()
self.state = 'restriction'
def action_paid(self):
self.state = 'paid'
def action_delivery(self):
self.state = 'delivery'
def action_done(self):
self.state = 'done'
def action_cancel(self):
self.state = 'cancel'
class YearPaymentLine(models.Model):
_name = 'benefit.zkat.line'
_rec_name = 'year_id'
year_id = fields.Many2one('benefit.zkat')
benefit_id = fields.Many2one('grant.benefit', string="Benefit")
responsible_id = fields.Many2one('grant.benefit', string="Responsible Benefit")
partner_id = fields.Many2one('res.partner', string="Responsible Partner")
category_id = fields.Many2one('benefit.category', string="Category")
date = fields.Datetime(string="Date")
state = fields.Selection(related="year_id.state", store=True)
amount = fields.Char(string="Amount")
# Payment collection
class PaymentCollection(models.Model):
_name = 'payment.collection.line'
receive_zkat_id = fields.Many2one(
'receive.benefit.zkat',
string='',
required=False)
donor_name = fields.Char(
string='Donor name',
required=False)
donor_partner = fields.Many2one('res.partner')
phone_number = fields.Char(
string='',
required=False)
payment_id = fields.Many2one('account.payment',
string='',
required=False)
donation_type = fields.Selection(
string='',
selection=[('material', 'Material'),
('cash', 'cash'),
('both', 'Both'),
],
required=False, )
currency_id = fields.Many2one('res.currency', string='Currency', related='payment_id.currency_id', readonly=True)
amount = fields.Monetary(
related='payment_id.amount',
string='Amount',
required=False)
quantity = fields.Float(
string='Quantity',
required=False)
class ZkatLine(models.Model):
_name = 'zkat.line'
zkat_id = fields.Many2one(
'benefit.zkat',
string='',
required=False)
family_id = fields.Many2one(
'benefit.family',
string='Family',
required=False)
benefits_total = fields.Integer(
related='family_id.benefits_total',
string='members',
required=False)
uint = fields.Float(
related='zkat_id.uint',
string='year amount',
required=False)
quantity = fields.Float(
compute='total_quantity',
string='Quantity',
required=False)
rate = fields.Float(
related='zkat_id.uint_amount',
string='Rate of zkat',
required=False)
net = fields.Float(
compute='total_net',
string='net of zkat',
required=False)
@api.onchange('uint')
def total_quantity(self):
for rec in self:
if rec.uint and rec.benefits_total:
rec.quantity = rec.uint * rec.benefits_total
self.quantity = 0
@api.onchange('quantity', 'rate')
def total_net(self):
for rec in self:
if rec.quantity and rec.rate:
if rec.rate < 100.00:
rec.net = rec.quantity * (rec.rate / 100)
else:
rec.net = rec.quantity * (100 / 100)
self.net = 0
self.net = 0

View File

@ -0,0 +1,10 @@
from odoo import fields, models, api
class BenefitServicesPayment(models.Model):
_inherit = "account.payment"
benefit_loan_id = fields.Many2one('benefit.loans')
receive_benefit_loan_id = fields.Many2one('receive.benefit.loans')
receive_food_basket = fields.Many2one('receive.food.basket')
receive_zkat = fields.Many2one('benefit.zkat')

View File

@ -0,0 +1,43 @@
from . import ir_attachment_inherit
from . import benefit
from . import education_status
from . import weak_course
from . import benefit_need
from . import benefit_config
from . import housing_config
from . import generate_reports
from . import Services
from . import sms
# from . import branch_inherit
from . import visit
from . import main_service
from . import member_location
from . import family_members
from . import member_diseases
from . import members_hobbies
from . import member_disabilities
from . import family_debits
from . import family_validation_setting
from . import expenses_type
from . import changes_requests
from . import education_settings
from . import education_period
from . import family_member_exam
from . import hr_department
from . import account_move_line
from . import family_expense
from . import family_expense_line
from . import services_settings
from . import res_country_inherit
from . import service_request
from . import payment_order
from . import family_complaints
from . import service_refuse_reason
from . import seasonal_service
# from . import res_config_settings
from . import res_users
from . import res_partner
from . import job_settings
from . import death_reason_settings
from . import benefit_vehicle_model
from . import visit_survey

View File

@ -0,0 +1,14 @@
from odoo import models,fields
class AccountMoveLine(models.Model):
_inherit = 'account.move.line'
benefit_family_id = fields.Many2one(comodel_name='grant.benefit', string='Benefit Family')
family_confirm_id = fields.Many2one(comodel_name='confirm.benefit.expense', string='Benefit Family')
family_code = fields.Char(string='Family Code', related='benefit_family_id.code',readonly=True)
class AccountMove(models.Model):
_inherit = 'account.move'
family_confirm_id = fields.Many2one(comodel_name='confirm.benefit.expense', string='Benefit Family')
benefit_family_ids = fields.Many2many(comodel_name='grant.benefit',relation='account_move_grant_family_rel',
column1='move_id',column2='family_id', string='Benefit Family')

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,900 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
from random import randint
from datetime import date
import logging
import os
_logger = logging.getLogger(__name__)
class BenefitCategory(models.Model):
_name = 'benefit.category'
_description = "Benefits - category"
name = fields.Char(string="Category Name")
description = fields.Char(string="Description")
gender = fields.Selection(selection=[('male', _('Male')), ('female', _('Female')) ,('both', _('Both'))], string="Gender")
age_from = fields.Integer(string="From")
age_to = fields.Integer(string="To")
benefit_ids = fields.One2many('grant.benefit', 'benefit_category_id', string="Category Benefits")
benefits_total = fields.Integer(string="Benefit Total", compute="get_benefits_total")
mini_income_amount = fields.Float(string="Min Income Amount")
max_income_amount = fields.Float(string="Max Income Amount")
expenses_ids = fields.One2many('expenses.line', 'category_id')
is_benefit = fields.Boolean(string="Is Benefit",default=True)
state = fields.Selection([('draft', 'Draft'),
('approve', 'Approved'),
('rejected', 'Rejected'), ], default='draft')
def get_benefits_total(self):
for rec in self:
rec.benefits_total = len(rec.benefit_ids)
def action_approve(self):
self.state = 'approve'
def action_reject(self):
self.state = 'rejected'
def open_benefits(self):
return {
'name': _("Benefits"),
'view_type': 'form',
'view_mode': 'tree,form',
'views': [(self.env.ref(
'odex_benefit.grant_benefit_tree').id, 'tree'),
(self.env.ref('odex_benefit.grant_benefit_form').id, 'form')],
'res_model': 'grant.benefit',
'type': 'ir.actions.act_window',
'domain': [('id', 'in', self.benefit_ids.ids)],
'target': 'current',
}
class GrantFamily(models.Model):
_name = 'benefit.family'
_description = "Benefits - family"
name = fields.Char(
string='',
required=False)
responsible_benefit_id = fields.Many2one(
'grant.benefit',
domain="[('is_responsible','=',True),('family_id','=',id)]")
housing_id = fields.Many2one(
'benefit.housing')
loan_ids = fields.Many2many('benefit.loans', 'family_id')
total_expenses = fields.Float(
compute='get_total_needs_percent',
string='Total Expenses of Family',
required=False)
total_income = fields.Float(
compute='get_total_needs_percent',
string='Total Income of Family',
required=False)
benefit_needs_percent = fields.Float(
compute='get_total_needs_percent',
string='',
store=True,
required=False)
is_producer = fields.Boolean(string='Producer')
description = fields.Char(string="Description")
benefits_total = fields.Integer(string="Benefit Total", compute="get_benefits_total", store=True)
benefit_ids = fields.One2many('grant.benefit', 'family_id', string="Benefits")
@api.depends("benefit_ids")
def get_benefits_total(self):
for rec in self:
rec.benefits_total = len(rec.benefit_ids)
def get_total_needs_percent(self):
for rec in self:
if rec.benefit_ids:
percent = 0.0
for amount in rec.benefit_ids:
rec.total_income += amount.total_income
rec.total_expenses += amount.total_expenses
percent += amount.benefit_needs_percent
rec.benefit_needs_percent = percent / len(rec.benefit_ids)
else:
rec.benefit_needs_percent = 0.0
rec.total_income = 0.0
rec.total_expenses = 0.0
def open_benefits(self):
return {
'name': "Benefits",
'view_type': 'form',
'view_mode': 'tree,form',
'views': [(self.env.ref(
'odex_benefit.grant_benefit_tree').id, 'tree'),
(self.env.ref('odex_benefit.grant_benefit_form').id, 'form')],
'res_model': 'grant.benefit',
'type': 'ir.actions.act_window',
'domain': "[('family_id','=',%s)]" % (self.id),
'target': 'current',
}
class SportLine(models.Model):
_name = 'sport.line'
_description = "Benefits - sport"
benefit_id = fields.Many2one(
'grant.benefit')
sport_type = fields.Many2one(
'sport.type')
sport_attendance = fields.Boolean(
string='',
required=False)
Subtype = fields.Selection(
string='Subtype',
selection=[('daily', 'daily'),
('monthly', 'Monthly'),
('yearly', 'yearly'),
], )
sport_time = fields.Selection(
string='Sport Time',
selection=[('morning', 'Morning'),
('day', 'day'),
('evening', 'evening'),
],
required=False, )
sport_club = fields.Char(
string='',
required=False)
sport_amount = fields.Float(
string='',
required=False)
sport_clothing = fields.Char(
string='',
required=False)
sport_equipment = fields.Char(
string='',
required=False)
class SportType(models.Model):
_name = 'sport.type'
_description = "Benefits - sport Type"
name = fields.Char(
string='',
required=False)
description = fields.Char(
string='Description',
required=False)
class CraftSkills(models.Model):
_name = 'craft.skills'
_description = "Benefits - sport"
name = fields.Char(
string='',
required=False)
benefit_id = fields.Many2one(
'grant.benefit')
is_invested = fields.Boolean(
string='',
required=False)
skill_rating = fields.Float(
string='',
required=False)
is_development = fields.Boolean(
string='',
required=False)
is_capital = fields.Boolean(
string='',
required=False)
is_work_place = fields.Boolean(
string='',
required=False)
work_history = fields.Char(
string='',
required=False)
achievements = fields.Char(
string='',
required=False)
certificates = fields.Binary(string="")
# Awards and certificates # TODO#
class inclination(models.Model):
_name = 'training.inclinations'
_description = "Benefits - inclination"
name = fields.Char(
string='',
required=False)
benefit_id = fields.Many2one(
'grant.benefit')
training_type_id = fields.Many2one('training.type',
string='',
required=False)
is_invested = fields.Boolean(
string='',
required=False)
training_rating = fields.Float(
string='',
required=False)
is_development = fields.Boolean(
string='',
required=False)
is_capital = fields.Boolean(
string='',
required=False)
training_history = fields.Char(
string='',
required=False)
book_history = fields.Char(
string='What books has he read?',
required=False)
courses = fields.Char(
string='What courses did he take?',
required=False)
steps = fields.Char(
string='',
required=False)
training_future = fields.Char(
string='',
required=False)
training_site = fields.Char(
string='',
required=False)
training_records = fields.Char(
string='',
required=False)
achievements = fields.Char()
certificates = fields.Binary(string="")
# Awards and certificates
class BenefitBehaviors(models.Model):
_name = 'benefit.behaviors'
_description = "Benefits - behaviors"
name = fields.Char(
related='behavior_id.name')
benefit_id = fields.Many2one(
'grant.benefit')
behavior_id = fields.Many2one(
'benefit.behaviors.type')
behavior_date = fields.Date(
string='',
required=False)
need_help = fields.Boolean(
string='',
required=False)
class BenefitBehaviorsType(models.Model):
_name = 'benefit.behaviors.type'
_description = "Benefits - behaviors type"
name = fields.Char(
string='',
required=False)
type = fields.Selection(
string='',
selection=[('negative', 'Negative'),
('positive', 'Positive'), ],
required=False, )
class Salary(models.Model):
_name = 'salary.line'
_description = "Benefits - Salary line"
benefit_id = fields.Many2one(
'grant.benefit')
currency_id = fields.Many2one('res.currency', related='benefit_id.currency_id')
salary_type = fields.Char()
income_type = fields.Many2one('attachments.settings',string='Income Type',domain="[('attach_type','=','income_attach')]")
salary_amount = fields.Float(
string='Income Amount',
required=False)
salary_attach = fields.Many2many('ir.attachment',string="Attachment")
attach_start_date = fields.Date(string='Attach Start Date')
attach_end_date = fields.Date(string='Attach End Date')
is_required = fields.Boolean(string='Is Required?')
is_mother_salary = fields.Boolean(string="Is Mother Salary", default=False)
approved = fields.Boolean(string="Is Approved", default=False)
is_default = fields.Boolean(string='Is Default?')
state = fields.Selection(string='Status',selection=[('waiting', 'Waiting'),('accepted', 'Accepted'),('refused', 'Refused')],default="waiting")
# total_salary = fields.Float(string="Total Salary", compute='_compute_total_salary',store=True)
# @api.depends('salary_amount','state')
# def _compute_total_salary(self):
# total = 0
# for record in self:
# # Apply your custom condition here
# records = self.env['salary.line'].search([('state', '=', 'accepted')])
# for rec in records:
# total += rec.salary_amount
# record.total_salary = total
@api.model
def create(self, vals):
if 'state' not in vals or vals.get('state') not in ['accepted', 'refused']:
vals['state'] = 'waiting'
return super(Salary, self).create(vals)
def write(self, vals):
if 'state' not in vals:
for rec in self:
if rec.state not in ['accepted', 'refused']:
vals['state'] = 'waiting'
break
return super(Salary, self).write(vals)
def action_accept(self):
self.state = 'accepted'
def action_refuse(self):
self.state = 'refused'
def get_salary_attachment_name(self):
"""Return salary attachment name without extension."""
if self.salary_attach:
return os.path.splitext(self.salary_attach.name)[0]
return ''
def get_notification_emails(self):
"""Return a list of valid emails to notify, removing False values."""
emails = self.benefit_id.researcher_id.employee_id.mapped('work_email') or []
emails.extend([
self.benefit_id.branch_custom_id.branch.manager_id.work_email,
self.benefit_id.branch_custom_id.branch.operation_manager_id.work_email
])
# Remove False or None values
emails = list(filter(None, emails)) # Filters out None and False values
return ','.join(emails) if emails else 'admin@example.com'
def action_send_attachment_expiry_email(self):
"""Send email notifications for attachments expiring today and log the body in the chatter."""
today = date.today()
salary_lines = self.search([('attach_end_date', '=', today)])
mail_template = self.env.ref('odex_benefit.email_salary_attachment_expiry')
if not mail_template:
raise ValidationError("Salary Attachment Expiry Mail template not found!")
for salary_line in salary_lines:
# Render the email body
email_body = mail_template._render_field('body_html', [salary_line.id], compute_lang=True)[salary_line.id]
# Send the email
mail_template.send_mail(salary_line.id, force_send=True)
# Post the email body in the chatter of benefit_id
if salary_line.benefit_id:
salary_line.benefit_id.message_post(
body=email_body,
subtype_xmlid="mail.mt_note" # Log as a note in the chatter
)
class ibanBanks(models.Model):
_inherit = 'res.bank'
_description = "Add iban details in bank screen"
iban = fields.Char("IBAN")
code = fields.Char(string='Code')
class benefitsExpensesLine(models.Model):
_name = 'benefit.expenses'
_description = "Benefits - expenses"
name = fields.Char()
benefit_id = fields.Many2one('grant.benefit')
expenses_type = fields.Selection(
string='',
selection=[('governmental', 'Governmental Expenses'),
('medical', 'Medical Expenses'),
('transportation', 'Transportation Expenses'),
('debts', 'Debts Expenses'),
('pandemics', 'Pandemics Expenses'),
('living', 'Living Expenses'),
('educational', 'Educational Expenses'),
('clothing', 'Clothing Expenses'),
],
required=False, )
expenses_fees_type = fields.Selection(
string='Fees Type',
selection=[('fixed', 'Fixed'),
('dynamic', 'dynamic')], required=False, )
medicine_type = fields.Selection(
string='Medicine Type',
selection=[('pills', 'pills'),
('drink', 'drink'),
('inhalation', 'inhalation')], required=False, )
diseases_type = fields.Selection(
string='Diseases Type',
selection=[('chronic', 'chronic'),
('psycho', 'psycho'),
('organic', 'organic')], required=False, )
trans_type = fields.Selection(
string='trans Type',
selection=[('general', 'General'),
('especially', 'Especially')], required=False, )
debt_reason = fields.Char(string='', required=False)
attach = fields.Binary(string="",attachment=True )
debt_type = fields.Selection(selection=[('necessary', 'Necessary'),
('need', 'Need'),
('improve', 'to improve'),
('case', 'case or not'),
('Installed', 'Installed or not'),
])
pandemics_explain = fields.Char(string='pandemics explain', required=False)
amount = fields.Float()
state = fields.Selection([('draft', 'Draft'),
('accreditation', 'Accreditation'),
], string='state', default="draft", tracking=True)
def action_accepted(self):
for i in self:
i.state = 'accreditation'
class cloth(models.Model):
_name = 'benefit.cloth'
name = fields.Char()
benefit_id = fields.Many2one('grant.benefit')
cloth_type = fields.Many2one('cloth.type')
cloth_size = fields.Many2one('cloth.size')
cloth_note = fields.Char()
class ClothType(models.Model):
_name = 'cloth.type'
name = fields.Char()
class ClothSize(models.Model):
_name = 'cloth.size'
name = fields.Char()
class ExpensesLine(models.Model):
_name = 'expenses.line'
category_id = fields.Many2one(
'benefit.category')
benefit_id = fields.Many2one('grant.benefit')
currency_id = fields.Many2one('res.currency', related='benefit_id.currency_id')
expenses_type_custom = fields.Many2one('expenses.type')
expenses_type = fields.Selection(
string='',
selection=[('governmental', 'Governmental Expenses'),
('medical', 'Medical Expenses'),
('transportation', 'Transportation Expenses'),
('debts', 'Debts Expenses'),
('pandemics', 'Pandemics Expenses'),
('living', 'Living Expenses'),
('educational', 'Educational Expenses'),
('clothing', 'Clothing Expenses'),
],
required=False, )
amount = fields.Float()
note = fields.Char()
state = fields.Selection(string='Status', selection=[('waiting', 'Waiting'),('accepted', 'Accepted'), ('refused', 'Refused')],default="waiting")
expense_attachments = fields.Many2many('ir.attachment','expenses_line_attachment_rel','expense_line_id','attachment_id',string="Attachment")
deduct_from_family_income = fields.Boolean(string="Deduct from Family Income")
def action_accept(self):
# self.benefit_id.get_member_income()
self.state = 'accepted'
def action_refuse(self):
self.state = 'refused'
class EntityRefuseReason(models.Model):
_name = 'entity.refuse_reason'
name = fields.Text("Refuse Reason")
user_id = fields.Many2one('res.users', 'Assigned to', default=lambda self: self.env.user, index=True)
entity_id = fields.Many2one('grant.benefit', 'Benefit Id')
date = fields.Datetime(string='Refuse Date', default=fields.Datetime.now)
class specialization(models.Model):
_name = 'specialization.specialization'
name = fields.Char(
string='',
required=False)
description = fields.Char(
string='Description',
required=False)
is_scientific_specialty = fields.Boolean('Is Scientific Specialty?')
is_medical_specialty = fields.Boolean('Is Medical Specialty?')
class OtherAssociations(models.Model):
_name = 'other.associations'
name = fields.Char(
string='',
required=False)
city_id = fields.Many2one(
'res.country.city')
description = fields.Char(
string='Description',
required=False)
class Associations(models.Model):
_name = 'associations.line'
benefit_id = fields.Many2one(
'grant.benefit')
associations_ids = fields.Many2one(
'other.associations',
string='Other Associations',
required=False)
support_type = fields.Selection(
string='',
selection=[('material', 'Material'),
('cash', 'cash'),
('both', 'Both'),
],
required=False, )
support_amount = fields.Float(
string='',
required=False)
associations_description = fields.Text(
string="",
required=False)
class Hospital(models.Model):
_name = 'hospital.hospital'
name = fields.Char(
string='',
required=False)
Location = fields.Char(
string='',
required=False)
class InsuranceCompany(models.Model):
_name = 'insurance.company'
name = fields.Char(
string='',
required=False)
description = fields.Char(
string='Description',
required=False)
class InsuranceType(models.Model):
_name = 'insurance.type'
name = fields.Char(
string='',
required=False)
description = fields.Char(
string='Description',
required=False)
class Cars(models.Model):
_name = 'cars.line'
name = fields.Char()
benefit_id = fields.Many2one('grant.benefit')
member_id = fields.Many2one('family.member',domain="[('benefit_id','=',benefit_id)]", string="Member")
car_model = fields.Many2one('benefit.vehicle.model', ondelete='restrict')
status = fields.Selection(
string='',
selection=[('good', 'Good'),
('bad', 'bad'), ],
required=False, ) # TODO
application_form = fields.Many2many('ir.attachment','cars_application_form_rel', 'cars_id','attachment_id',string="Application Form")
driving_license = fields.Many2many('ir.attachment','cars_driving_license_rel','cars_id','attachment_id',string="Driving License")
owner_identity = fields.Many2many('ir.attachment','cars_owner_identity_rel','cars_id', 'attachment_id',string="Owner Identity")
class TrainingType(models.Model):
_name = 'training.type'
name = fields.Char()
class Committees(models.Model):
_name = 'committees.line'
name = fields.Char()
employee_id = fields.Many2many('hr.employee')
type = fields.Selection(
string='',
selection=[('male', 'Men'),
('female', 'women'),
('both', 'combined'),
],
required=False, )
branch_custom_id = fields.Many2one("branch.settings", string="Branch")
active = fields.Boolean('Active', default=True)
benefit_count = fields.Integer(compute="get_benefit_count")
def get_benefit_count(self):
for record in self:
benefit_ids = self.env['grant.benefit'].search([('researcher_id', 'in', record.ids)])
record.benefit_count = len(benefit_ids)
def action_view_benefits(self):
return {
'name': _('Benefits'),
'type': 'ir.actions.act_window',
'res_model': 'grant.benefit',
'view_mode': 'tree,form',
'domain': [('researcher_id', 'in', self.ids)],
'target': 'current',
}
class ResDistricts(models.Model):
_name = 'res.districts'
name = fields.Char(string="Name")
meal_card = fields.Boolean(string='Meal Card')
city_id = fields.Many2one('res.country.city')
branch_custom_id = fields.Many2one("branch.settings", string="Branch", domain="[('city_id', '=', city_id)]")
class VisitsSettings(models.Model):
_name = 'visits.types'
name = fields.Char(string="Name", required=True)
creation_method = fields.Selection(
[('manual', 'Manual'),('automatic', 'Automatic')],
string="Creation Method",
default='manual',
required=True,
help="Whether the visit is entered manually or created automatically"
)
recurrence_interval = fields.Integer(
string="Recurrence Interval",
default=1,
help="Determines how often visits are created automatically"
)
recurrence_period = fields.Selection([
('days', 'Days'),
('weeks', 'Weeks'),
('months', 'Months')
], string="Recurrence Period", default='days',
help="Time unit for recurrence")
otp_verification = fields.Boolean(
string="OTP Verification",
default=False,
help="Whether this visit requires OTP confirmation from the family"
)
otp_validity_minutes = fields.Integer(
string="OTP Validity (Minutes)",
default=5,
help="OTP code validity duration in minutes"
)
active = fields.Boolean(
string="Active",
default=True
)
survey_id = fields.Many2one(
'survey.survey',
string="Evaluation Survey"
)
class SurveySetting(models.Model):
_name = 'survey.setting'
survey_url = fields.Char("Survey URL")
class SuspendReason(models.Model):
_name = 'suspend.reason'
_description = "Suspend - Reason"
name = fields.Char(string="Name", required=True)
is_stop_reason = fields.Boolean(string="Stop Reason",default=False)
is_reject_reason = fields.Boolean(string="Reject Reason",default=False)
is_return_reason = fields.Boolean(string="Return Reason",default=False)
is_family_return_reason = fields.Boolean(string="Family Return Reason",default=False)
is_incomplete_visit_reason = fields.Boolean(string="Incomplete Visit Reason",default=False)
active = fields.Boolean(default=True)
class ReturnReason(models.Model):
_name = "return.reason"
_description = "Return Reasons"
name = fields.Char(string="Name", required=True)
active = fields.Boolean(string="Active", default=True)
class BranchSettings(models.Model):
_name = 'branch.settings'
_description = "Branch Settings"
name = fields.Char(related='branch.name')
branch = fields.Many2one('hr.department',string='Branch',domain =[('is_branch', '=', True)])
branch_type = fields.Selection(
selection=[
('branches', 'Branches'),
('governorates', 'Governorates')],
string='Branch Type')
city_id = fields.Many2one('res.country.city')
has_employees = fields.Boolean('Has Employees' ,defualt=True)
class RelationSettings(models.Model):
_name = 'relation.settings'
_description = "Relation Settings"
name = fields.Char(string='name')
relation_type = fields.Selection(
[('son', _('Son')), ('daughter', _('Daughter')),('mother', _('Mother')),('replacement_mother', _('Replacement Mother')),('other relation', _('Other Relation'))])
age_difference = fields.Integer()
class LocationSettings(models.Model):
_name = 'location.settings'
_description = "Location Settings"
name = fields.Char(string='name')
location_type = fields.Selection([('member', _('Member')), ('mother_location', _('Mother Location'))])
is_benefit = fields.Boolean(string='Is Benefit?')
is_far_from_family = fields.Boolean(string='Is Far From Family?')
class AttachmentsSettings(models.Model):
_name = 'attachments.settings'
_description = "Attachments Settings"
_order = 'family_appearance_seq,member_appearance_seq,income_appearance_seq asc'
name = fields.Char(string='name')
hobby_id = fields.Many2one('hobbies.settings',string='Hobbies')
diseases_id = fields.Many2one('diseases.settings',string='Diseases')
disabilities_id = fields.Many2one('disabilities.settings',string='Disabilities')
attach_type = fields.Selection(
[('family_attach', _('Family Attach')), ('member_attach', _('Member Attach')), ('hobbies_attach', _('Hobbies Attach')),
('diseases_attach', _('Diseases Attach')), ('disabilities_attach', _('Disabilities Attach')), ('income_attach', _('Income Attach')), ('exams_attach', _('Exams Attach'))])
is_required = fields.Boolean(string='Is Required?')
is_default = fields.Boolean(string='Is Default?')
show_in_portal = fields.Boolean(default=True)
family_appearance_seq = fields.Integer(string='Appearance Sequence')
member_appearance_seq = fields.Integer(string='Appearance Sequence')
income_appearance_seq = fields.Integer(string='Appearance Sequence')
is_mother_salary = fields.Boolean(string="Is Mother Salary", default=False)
class EducationIlliterateReason(models.Model):
_name = 'education.illiterate.reason'
_description = "Education Illiterate Reason"
name = fields.Char(string='name')
class EducationDelayReason(models.Model):
_name = 'education.delay.reason'
_description = "Education Delay Reason"
name = fields.Char(string='Name', required=True)
class IncomeType(models.Model):
_name = 'income.type'
_description = "Income Type"
name = fields.Char(string='name')
class LoanGiver(models.Model):
_name = 'loan.giver'
_description = "LoanGiver"
name = fields.Char(string='name')
class LoanReason(models.Model):
_name = 'loan.reason'
_description = "Loan Reason"
name = fields.Char(string='name')
class HobbiesSettings(models.Model):
_name = 'hobbies.settings'
name = fields.Char(string="Name")
class DiseasesSettings(models.Model):
_name = 'diseases.settings'
name = fields.Char(string="Name")
class DisabilitiesSettings(models.Model):
_name = 'disabilities.settings'
name = fields.Char(string="Name")
class ExceptionReason(models.Model):
_name = 'exception.reason'
name = fields.Char(string="Name")
class MaritalStatus(models.Model):
_name = 'marital.status'
name = fields.Char(string="Name")
is_benefit = fields.Boolean(string='Is Benefit?')
is_dead = fields.Boolean(string='Is Dead?')
class AgeCategory(models.Model):
_name = 'age.category'
min_age = fields.Integer(string="From")
max_age = fields.Integer(string="To")
name = fields.Char(string="Name", compute="_compute_name", store=True)
@api.depends('min_age', 'max_age')
def _compute_name(self):
for record in self:
if record.min_age is not None and record.max_age is not None:
record.name = f"[{record.min_age}:{record.max_age}]"
else:
record.name = ""
class ComplaintsCategory(models.Model):
_name = 'complaints.category'
def _get_default_color(self):
return randint(1, 11)
name = fields.Char('Category Name', required=True, translate=True)
color = fields.Integer('Color', default=_get_default_color)
class ServiceAttachmentsSettings(models.Model):
_name = 'service.attachments.settings'
_description = "Service Attachments Settings"
name = fields.Char(string='name')
service_attach = fields.Many2many('ir.attachment','rel_service_attachments', 'service_id', 'attach_id',string="Attachment")
service_type = fields.Selection(
[('rent', 'Rent'), ('home_restoration', 'Home Restoration'), ('alternative_housing', 'Alternative Housing'),
('home_maintenance', 'Home Maintenance'), ('complete_building_house', 'Complete Building House'), ('electrical_devices', 'Electrical Devices'),
('home_furnishing', 'Home furnishing')
, ('electricity_bill', 'Electricity bill'), ('water_bill', 'Water bill'), ('buy_car', 'Buy Car'),
('recruiting_driver', 'Recruiting Driver')
, ('transportation_insurance', 'Transportation Insurance'), ('debits', 'Debits'),
('health_care', 'Health Care'),
('providing_medicines_medical_devices_and_needs_the_disabled',
'Providing Medicines Medical Devices And Needs The Disabled'),
('recruiting_domestic_worker_or_nurse', 'Recruiting a domestic worker or nurse'), ('marriage', 'Marriage'),
('eid_gift', 'Eid gift'),
('winter_clothing', 'Winter clothing'), ('ramadan_basket', 'Ramadan basket'),
('natural_disasters', 'Natural disasters'), ('legal_arguments', 'Legal arguments')],string='Service Type',related="service_id.service_type")
service_id = fields.Many2one('services.settings',string='Service')
service_request_id = fields.Many2one('service.request',string='Service Request')
previous_service_attachment_settings_id = fields.Many2one('service.attachments.settings', readonly=True)
notes = fields.Text(string='Notes')
class HomeMaintenanceItems(models.Model):
_name = 'home.maintenance.items'
maintenance_items_id = fields.Many2one('home.maintenance.lines', string="Maintenance Items")
service_request_id = fields.Many2one('service.request',string='Service Request')
class HomeFurnishingItems(models.Model):
_name = 'home.furnishing.items'
home_furnishing_items = fields.Many2one('home.furnishing.lines', string='Furnishing Items')
furnishing_cost = fields.Float(string='Furnishing Cost')
price_first = fields.Float(string='Price First')
price_first_attach = fields.Many2many('ir.attachment','rel_first_price_attachments', 'furnishing_id', 'attach_id',string="First Price Attachment")
price_second = fields.Float(string='Price Second')
price_second_attach = fields.Many2many('ir.attachment','rel_second_price_attachments', 'furnishing_id', 'attach_id',string="Second Price Attachment")
service_request_id = fields.Many2one('service.request',string='Service Request')

View File

@ -0,0 +1,329 @@
from odoo import fields, models, api, _
class BenefitsNeeds(models.Model):
_name = 'benefits.needs'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = 'percentage of need of benefit '
name = fields.Char(string='', required=False)
benefit_need_type = fields.Selection(
string='',
selection=[('special', 'special (for one)'),
('general', 'general(for group)'), ],
required=False, )
date = fields.Datetime(
string='',
required=False)
benefit_id = fields.Many2one(
'grant.benefit',
string='',
required=False)
description = fields.Char(
string='',
required=False)
benefit_type = fields.Selection(
string='Benefits Type',
selection=[('orphans', _('orphans')),
('widows', _('widows')),
('both', _('Both')),
],
compute='_onchange_benefit_ids',
required=False, store=True)
need_status = fields.Selection(string='',
selection=[('urgent', 'urgent'),
('not_urgent', 'Not urgent'), ],
required=False, )
need_category = fields.Many2one('needs.categories', required=False)
category_name = fields.Char(related='need_category.name')
need_type_ids = fields.Many2many('product.product', string='')
city_id = fields.Many2one('res.country.city')
city_name = fields.Char(related='city_id.name')
benefit_ids = fields.Many2many('grant.benefit', string='')
target_amount = fields.Float(string='', compute="_onchange_paid_amount")
f_amount = fields.Float(string='')
paid_amount = fields.Float(string='', compute='_onchange_paid_amount')
remaining_amount = fields.Float(string='', compute='_onchange_paid_amount')
completion_ratio = fields.Float(string='', compute='_onchange_paid_amount')
payments_ids = fields.One2many('needs.payment.line', 'need_id')
need_attach = fields.Binary(string="", )
state = fields.Selection([
('draft', 'Draft'),
('sent', 'sent'),
('review', 'Under Review'),
('approve', 'Approved'),
('published', 'Published'),
('refused', 'Refused'),
('done', 'Done'),
], string='state', default="draft", tracking=True)
benefit_count = fields.Integer(string='Benefits count for needs',
compute='_compute_needs_benefit_count', store=True)
@api.depends('benefit_id', 'benefit_ids')
def _compute_needs_benefit_count(self):
""" Calculate needs benefits count """
for rec in self:
if rec.benefit_ids:
rec.benefit_count = len(rec.benefit_ids)
elif rec.benefit_id:
rec.benefit_count = 1
else:
rec.benefit_count = 0
def action_submit(self):
for rec in self:
rec.state = 'sent'
def action_review(self):
for rec in self:
rec.state = 'review'
def action_approve(self):
for rec in self:
rec.state = 'approve'
def action_published(self):
for rec in self:
rec.state = 'published'
def action_refused(self):
for rec in self:
rec.state = 'refused'
def action_done(self):
for rec in self:
rec.state = 'done'
@api.onchange('need_category')
def _onchange_need_category(self):
for rec in self:
need_list = []
for i in rec.need_category.product_ids:
need_list.append(i.id)
rec.need_type_ids = [(6, 0, need_list)]
@api.onchange('benefit_ids', 'benefit_id')
def _onchange_benefit_ids(self):
for rec in self:
b_type = []
if rec.benefit_ids:
for i in rec.benefit_ids:
b_type.append(i.benefit_type)
if rec.benefit_id:
for i in rec.benefit_id:
b_type.append(i.benefit_type)
if 'orphan' in b_type and 'widow' not in b_type:
rec.benefit_type = 'orphans'
if 'widow' in b_type and 'orphan' not in b_type:
rec.benefit_type = 'widows'
if 'widow' in b_type and 'orphan' in b_type:
rec.benefit_type = 'both'
if b_type == []:
rec.benefit_type = False
@api.onchange('need_type_ids', 'paid_amount', 'need_category')
def _onchange_paid_amount(self):
for rec in self:
paid_amount = 0.0
target_amount = 0.0
for pay in rec.payments_ids:
if pay.state == 'paid':
paid_amount += pay.amount
rec.paid_amount = format(paid_amount, '.2f')
for i in rec.need_type_ids:
if rec.f_amount > 0:
target_amount = rec.f_amount
else:
target_amount += i.lst_price
rec.target_amount = format(target_amount, '.2f')
if rec.target_amount:
remaining_amount = format(rec.target_amount - rec.paid_amount, '.2f')
rec.remaining_amount = remaining_amount
if not rec.target_amount == 0.0 and rec.target_amount >= rec.paid_amount:
completion_ratio = 100 - ((rec.remaining_amount / rec.target_amount) * 100)
rec.completion_ratio = format(completion_ratio, '.2f')
else:
rec.completion_ratio = 0.0
else:
rec.remaining_amount = 0.0
rec.completion_ratio = 0.0
# else:
# raise ValidationError(
# _(u' You cant Add pay anymore'))
class Payments(models.Model):
_name = 'needs.payment.line'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = 'Payments'
need_id = fields.Many2one('benefits.needs')
invoice_id = fields.Many2one('account.move')
partner_id = fields.Many2one('res.partner', related="invoice_id.partner_id")
amount = fields.Monetary(related="invoice_id.amount_total")
currency_id = fields.Many2one('res.currency', string='Currency', readonly=True, related="invoice_id.currency_id")
state = fields.Selection([
('draft', 'Draft'),
('open', 'Open'),
('paid', 'Paid'),
('cancel', 'Cancelled'), ], store=True, related="invoice_id.state")
date = fields.Date(related="invoice_id.invoice_date")
class NeedsCategories(models.Model):
_name = 'needs.categories'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = 'Categories of need of benefit '
name = fields.Char(
string='',
required=False)
description = fields.Char(
string='',
required=False)
product_ids = fields.Many2many('product.product')
class PercentageOfNeed(models.Model):
_name = 'benefit.need'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = 'percentage of need of benefit '
name = fields.Char()
housing_id = fields.Many2one(
'benefit.housing',
string='',
tracking=True,
required=False)
benefit_ids = fields.One2many('grant.benefit', 'housing_id', string="Benefits")
house_need = fields.One2many(
comodel_name='house.need',
inverse_name='benefit_need_id',
string='',
required=False)
total_expenses = fields.Float(
compute='_get_total_expenses',
store=True,
tracking=True,
string='',
required=False)
expenses_ids = fields.Many2many(
comodel_name='grant.benefit',relation='grant_benefit_group_rel',compute='_get_total_expenses',column1='benefit_id',column2='grant_id',tracking=True,
store=True,
string='',
required=False)
income_ids = fields.Many2many(
'grant.benefit',
compute='_get_total_income',
tracking=True,
store=True,
string='',
required=False)
total_income = fields.Float(
compute='_get_total_income',
tracking=True,
store=True,
string='total income',
required=False)
total_net = fields.Float(
string='net',
store=True,
compute='_get_total_net',
tracking=True,
required=False)
financial_aid = fields.Float(
string='Financial Aid',
store=True,
compute='_get_total_net',
tracking=True,
required=False)
state = fields.Selection([
('draft', 'Draft'),
('visit', 'field visit'),
('waiting_approve', 'Waiting Approved'),
('approve', 'Approved'),
('refused', 'Refused'),
], string='state', default="draft", tracking=True)
def action_visit(self):
self.state = 'visit'
def action_waiting_approve(self):
self.state = 'waiting_approve'
def action_approve(self):
self.state = 'approve'
def action_refused(self):
self.state = 'refused'
@api.depends('housing_id')
def _get_total_expenses(self):
for rec in self:
if rec.state == 'draft':
benefit_id = rec.env['grant.benefit'].sudo().search([('housing_id', '=', rec.housing_id.id)])
benefit_ids = rec.env['grant.benefit'].sudo().search(
[('housing_id', '=', rec.housing_id.id), ('benefit_type', '=', 'benefit')])
benefit = []
total_expenses = 0.0
for i in benefit_id:
benefit.append(i.id)
total_expenses += i.total_expenses
for r in self:
r.expenses_ids = [(6, 0, benefit)]
r.total_expenses = total_expenses
@api.depends('housing_id')
def _get_total_income(self):
for rec in self:
if rec.state == 'draft':
benefit_ids = rec.env['grant.benefit'].sudo().search(
[('housing_id', '=', rec.housing_id.id), ('benefit_type', '=', 'benefit')])
benefit = []
total_income = 0.0
for i in benefit_ids:
benefit.append(i.id)
total_income += i.total_income
for r in rec:
r.income_ids = [(6, 0, benefit)]
r.total_income = total_income
@api.depends('housing_id')
def _get_total_net(self):
for rec in self:
if rec.state == 'draft':
rec.total_net = 0.0
rec.financial_aid = 0.0
if rec.total_expenses >= rec.total_income:
rec.total_net = rec.total_expenses - rec.total_income
else:
rec.total_net = rec.total_income - rec.total_expenses
if rec.total_net < 0:
rec.financial_aid = (abs(rec.total_net) * .5)
class HouseNeed(models.Model):
_name = 'house.need'
_description = 'House Need'
benefit_need_id = fields.Many2one(
'benefit.need',
string='',
required=False)
housing_id = fields.Many2one(
'benefit.housing',
string='',
related="benefit_need_id.housing_id",
required=False)
room_id = fields.Many2one(
'benefit.housing.rooms',
string='',
domain="[('housing_id', '=', housing_id)]",
required=False)
needs = fields.Char(
string='',
required=False)
needs_percentage = fields.Float(
string='',
required=False)

View File

@ -0,0 +1,14 @@
from odoo import fields, models,api,_
from odoo.exceptions import UserError, ValidationError
class BenefitVehicleModel(models.Model):
_name = 'benefit.vehicle.model'
_description = "Vehicle Model"
_inherit = ['mail.thread', 'mail.activity.mixin']
name = fields.Char(string="Name", required=True, tracking=True)
active = fields.Boolean(default=True)
_sql_constraints = [
("name_unique", "unique(name)", _("The name must be unique.")),
]

View File

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
class BranchInherit(models.Model):
_inherit = 'res.branch'
district_id = fields.Many2one('res.districts', string="District")

View File

@ -0,0 +1,117 @@
from odoo import fields, models, api, _
class ChangesRequests(models.Model):
_name = 'changes.requests'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = 'Changes Requests'
name = fields.Char()
change_type = fields.Selection(
string='Change Type',
selection=[
('transfer_family_from_research_to_another_research', 'Transfer Family From Research To Another Research'),
('transfer_family_from_branch_to_another_branch', 'Transfer Family From Branch To Another Branch'),
('transfer_research_from_branch_to_another_branch', 'Transfer Research From Branch To Another Branch')],default="transfer_family_from_research_to_another_research")
benefit_id = fields.Many2one("grant.benefit", string='Family')
researcher_id = fields.Many2one("committees.line",compute="get_researcher_id",string='Researcher Team',store=True)
branch_custom_id = fields.Many2one("branch.settings",compute="get_branch_id",string='Branch',store=True)
new_branch_id = fields.Many2one("branch.settings",string='New Branch')
new_researcher_id = fields.Many2one("committees.line", domain ="['&',('branch_custom_id','=',branch_custom_id),('id','!=',researcher_id)]",string='New Researcher Team')
new_branch_researcher = fields.Many2one("committees.line", domain ="[('branch_custom_id','=',new_branch_id)]",string='New Researcher Team')
execution_date = fields.Datetime(string="Transfer Execution Date")
state = fields.Selection(
string='State',
selection=[
('draft', 'Draft'),
('approval_of_department_head', 'Approval of department head'),
('approval_of_branch_manager', 'Approval of branch manager')]
,default = 'draft')
team_type = fields.Selection(
string='Team Type',
selection=[
('male', 'Male'),
('female', 'Female'),
('both', 'Both')])
gender_researcher_id = fields.Many2one("committees.line",domain ="[('type','=',team_type)]",string='Researcher Team')
is_whole_team = fields.Boolean(string='Is Whole Team?')
researcher_branch_id = fields.Many2one("branch.settings",compute = "get_researcher_branch_id", store = True,string='Branch')
new_gender_researcher_id = fields.Many2one("committees.line",domain ="['&',('branch_custom_id','=',researcher_branch_id),('id','!=',gender_researcher_id)]",string='Alternative Researcher Team for family')
new_gender_researcher_one = fields.Many2one("committees.line",domain ="[('branch_custom_id','=',new_branch_id)]",string='Alternative Researcher Team for researcher')
researcher_ids = fields.Many2many("hr.employee", string="Researcher",readonly=False)
@api.onchange('gender_researcher_id')
def item_researcher_ids_onchange(self):
return {'domain': {'researcher_ids': [('id', 'in', self.gender_researcher_id.employee_id.ids)]}}
@api.depends("benefit_id")
def get_researcher_id(self):
for rec in self:
rec.researcher_id = rec.benefit_id.researcher_id
@api.depends("benefit_id")
def get_branch_id(self):
for rec in self:
rec.branch_custom_id = rec.benefit_id.branch_custom_id
@api.depends("gender_researcher_id")
def get_researcher_branch_id(self):
for rec in self:
rec.researcher_branch_id = rec.gender_researcher_id.branch_custom_id
def approval_of_department_head_c1(self):
for rec in self:
rec.state = 'approval_of_department_head'
def approval_of_branch_manager_c1(self):
for rec in self:
rec.state = 'approval_of_branch_manager'
rec.benefit_id.researcher_id = rec.new_researcher_id
message = "Your family has been transferred to another researcher team %s"% (self.new_researcher_id.name)
mail = self.env['mail.mail'].create({
'body_html': message,
'subject': "transferred to another researcher team",
'email_to': self.benefit_id.email,
})
mail.send()
def approval_of_department_head_c2(self):
for rec in self:
rec.state = 'approval_of_department_head'
def approval_of_branch_manager_c2(self):
for rec in self:
rec.state = 'approval_of_branch_manager'
rec.benefit_id.branch_custom_id = rec.new_branch_id
rec.benefit_id.researcher_id = rec.new_branch_researcher
message = "Your family has been transferred to another branch %s" % (self.new_branch_id.name)
mail = self.env['mail.mail'].create({
'body_html': message,
'subject': "Transferred to another branch",
'email_to': self.benefit_id.email,
})
mail.send()
def approval_of_department_head_c3(self):
for rec in self:
rec.state = 'approval_of_department_head'
def approval_of_branch_manager_c3(self):
obj = self.env["grant.benefit"].search([])
for rec in self:
rec.state = 'approval_of_branch_manager'
rec.gender_researcher_id.branch_custom_id = rec.new_branch_id
for item in obj.filtered(lambda r: r.researcher_id == rec.gender_researcher_id):
item.researcher_id = rec.new_gender_researcher_id
if rec.is_whole_team == False:
for employee in rec.gender_researcher_id.employee_id:
for i in rec.researcher_ids:
if employee.id == i.id:
rec.gender_researcher_id.sudo().write({'employee_id':[(3,employee.id)]})
rec.new_gender_researcher_one.sudo().write({'employee_id':[(4,employee.id)]})
message = "Your family has been transferred to another branch %s" % (self.new_branch_id.name)
mail = self.env['mail.mail'].create({
'body_html': message,
'subject': "Transferred to another branch",
'email_to': self.benefit_id.email,
})
mail.send()
# for rec in self.benefit_id.researcher_id.employee_id:
# rec.benefit_id.researcher_id

View File

@ -0,0 +1,18 @@
from odoo import models, fields, _
class DeathReasonSettings(models.Model):
_name = 'death.reason.settings'
name = fields.Char(required=True)
not_defined = fields.Boolean(default=False)
active = fields.Boolean(default=True)
_sql_constraints = [
(
'uniq_name',
'UNIQUE( name )',
_('This death reason already exists!')
)
]

View File

@ -0,0 +1,13 @@
from odoo import fields, models,api
class EducationPeriod(models.Model):
_name = 'education.period'
_description = 'Education Period'
_order = 'id desc'
name = fields.Char(string="Name", required=True)
start_date = fields.Date(string='Period Start Date', required=True)
end_date = fields.Date(string='Period End Date', required=True)
education_level_ids = fields.Many2many('education.level', string='Education Levels')
education_entity_ids = fields.Many2many("education.entities", string='Education Entities')

View File

@ -0,0 +1,53 @@
from odoo import fields, models,api
class EducationEntities(models.Model):
_name = 'education.entities'
name = fields.Char(string='Name')
education_level_id = fields.Many2one('education.level', string='Education Level')
class EducationLevel(models.Model):
_name = 'education.level'
name = fields.Char(string='Name')
level_expected_age = fields.Float(string="Level Expected Age")
class EducationClassroom(models.Model):
_name = 'education.classroom'
name = fields.Char(string='Name')
education_level_id = fields.Many2one('education.level', string='Education Level')
class EducationResults(models.Model):
_name = 'education.result'
name = fields.Char(string='Name',compute="get_name")
evaluation = fields.Char(string='Evaluation')
rate_type = fields.Selection([
('from_4', 'From 4'),
('from_5', 'From 5'),
('from_100', 'From 100'),
], string='Rate Type')
min_degree = fields.Float(string='Mini Degree')
max_degree = fields.Float(string='Max Degree')
@api.depends("evaluation","min_degree","max_degree")
def get_name(self):
for rec in self:
if rec.evaluation and rec.max_degree and rec.min_degree:
rec.name = rec.evaluation + " " + str(rec.min_degree) + "-" + str(rec.max_degree)
else:
rec.name=""
class StudyMaterial(models.Model):
_name = 'study.material'
name = fields.Char(string='Name')
class EducationExamType(models.Model):
_name = 'education.exam.type'
name = fields.Char(string='Name', required=True)

View File

@ -0,0 +1,204 @@
from odoo import models, fields, api, _
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
from dateutil.relativedelta import relativedelta as rd
from datetime import datetime, date
class EducationStatus(models.Model):
_name = 'education.status'
_order = 'education_status_type asc, name desc'
mother_grant_benefit_id = fields.Many2one('grant.benefit', string='Grant Benefit')
replacement_grant_benefit_id = fields.Many2one('grant.benefit', string='Grant Benefit')
family_member_id = fields.Many2one('family.member', string='Grant Benefit')
name = fields.Char(
string="Sequence",
default="/",
readonly=True,
copy=False,
index=True
)
education_status_type = fields.Selection(
selection=[
('current', 'Current'),
('previous', 'Previous')
],
required=False, compute="_compute_education_status_type", store=True
)
education_status = fields.Selection(
string='Education Status',
selection=[
('educated', 'Educated'),
('illiterate', 'Illiterate'),
('under_study_age', 'Under Study Age')
],
compute="_compute_education_status",
# store=True
)
case_study = fields.Selection(
string='Case Study',
selection=[('continuous', 'Continuous'),
('intermittent', 'Intermittent'),
('graduate', 'Graduate')]
)
education_entity = fields.Selection(
string='Education Entity',
selection=[('governmental', 'Governmental'),
('special', 'Special')]
)
education_start_date = fields.Date(string='Education Start Date')
education_end_date = fields.Date(string='Education End Date')
educational_certificate = fields.Many2many(
'ir.attachment',
'rel_education_status_educational_certificate_attachment',
'education_status_id',
'attachment_id',
string='Educational Certificate'
)
education_levels = fields.Many2one("education.level", string='Education Levels')
entities = fields.Many2one("education.entities", string='Entity',
domain="[('education_level_id', '=', education_levels)]")
education_period_id = fields.Many2one("education.period", string='Education Period', domain="['|', '|', ('education_level_ids', 'in', education_levels), ('education_level_ids', '=', False),'|',('education_entity_ids', 'in', entities), ('education_entity_ids', '=', False)]")
classroom = fields.Many2one('education.classroom', string='Classroom',
domain="[('education_level_id', '=', education_levels)]")
rate_type = fields.Selection([
('from_4', 'From 4'),
('from_5', 'From 5'),
('from_100', 'From 100'),
], string='Rate Type')
degree = fields.Many2one('education.result', string='Degree')
percentage = fields.Float(string="Percentage%")
specialization_ids = fields.Many2one('specialization.specialization', string='Specialization')
intermittent_reason_id = fields.Many2one('education.illiterate.reason', string='Intermittent Reason')
intermittent_date = fields.Date(string='Intermittent Date')
family_member_age = fields.Integer(string="Age At Level Beginning", compute='_compute_family_member_age',
store=True)
family_member_delay = fields.Boolean(string="Member Delay", compute='_compute_family_member_delay', store=True)
delay_reason_id = fields.Many2one('education.delay.reason', string='Delay Reason')
weak_course_ids = fields.One2many('weak.course', 'education_status_id')
@api.depends(
'mother_grant_benefit_id',
'mother_grant_benefit_id.education_status',
'replacement_grant_benefit_id',
'replacement_grant_benefit_id.replacement_education_status',
'family_member_id',
'family_member_id.education_status',
)
def _compute_education_status(self):
for record in self:
record.education_status = record.mother_grant_benefit_id.education_status or \
record.replacement_grant_benefit_id.replacement_education_status or \
record.family_member_id.education_status
@api.depends("case_study")
def _compute_education_status_type(self):
for rec in self:
if rec.case_study:
if rec.case_study == "continuous":
rec.education_status_type = "current"
else:
rec.education_status_type = "previous"
else:
rec.education_status_type = False
@api.depends("education_start_date", "family_member_id", "family_member_id.birth_date")
def _compute_family_member_age(self):
for rec in self:
if rec.education_start_date and rec.family_member_id and rec.family_member_id.birth_date:
day = datetime.strptime(str(rec.family_member_id.birth_date), DEFAULT_SERVER_DATE_FORMAT)
age = rd(rec.education_start_date, day)
rec.family_member_age = age.years
else:
rec.family_member_age = 0
@api.depends("family_member_age", "education_levels", "education_levels.level_expected_age")
def _compute_family_member_delay(self):
for rec in self:
if rec.family_member_age > 0 and rec.education_levels and rec.education_levels.level_expected_age > 0:
if rec.family_member_age > rec.education_levels.level_expected_age:
rec.family_member_delay = True
else:
rec.family_member_delay = False
else:
rec.family_member_delay = False
@api.onchange('education_status_type')
def _onchange_education_status_type(self):
relation_id = self.mother_grant_benefit_id or \
self.replacement_grant_benefit_id or \
self.family_member_id
if self.education_status_type == 'current' and relation_id:
existing_current = self.search([
('education_status_type', '=', 'current'),
'|', '|',
('mother_grant_benefit_id', '=', relation_id._origin.id),
('replacement_grant_benefit_id', '=', relation_id._origin.id),
('family_member_id', '=', relation_id._origin.id)
], limit=1)
if existing_current:
return {
"warning": {
'title': _('Current Education Status Already Exists'),
'message': _(
"There is already an education status marked as Current.\nIf you save this, %s will be marked as Previous!") % existing_current.name
}
}
@api.onchange('education_period_id', 'education_period_id.start_date', 'education_period_id.end_date')
def _onchange_field_name(self):
self.ensure_one()
if self.education_period_id:
if self.education_period_id.start_date:
self.education_start_date = self.education_period_id.start_date
if self.education_period_id.end_date:
self.education_end_date = self.education_period_id.end_date
@api.model
def create(self, vals):
# Determine the prefix based on the related field
prefix = 'EDU/'
relation_field = False
if vals.get('mother_grant_benefit_id'):
prefix = 'EDUM/'
relation_field = 'mother_grant_benefit_id'
elif vals.get('replacement_grant_benefit_id'):
prefix = 'EDUR/'
relation_field = 'replacement_grant_benefit_id'
elif vals.get('family_member_id'):
prefix = 'EDUF/'
relation_field = 'family_member_id'
# Build domain filter to count records for the same category
domain = [('name', 'like', prefix)]
if relation_field and vals.get(relation_field):
domain.append((relation_field, '=', vals.get(relation_field)))
# Get the count of existing records with the same prefix & relation ID
existing_count = self.search_count(domain) + 1
formatted_number = str(existing_count).zfill(4) # Format as 4-digit number
# Assign computed sequence name
vals['name'] = f"{prefix}{formatted_number}"
# Ensure only one 'current' education status exists
relation_id = vals.get('mother_grant_benefit_id',
vals.get('replacement_grant_benefit_id', vals.get('family_member_id', False)))
if not self.env.context.get('skip_current_check') and vals.get(
'education_status_type') == 'current' and relation_id:
existing_current = self.search([
('education_status_type', '=', 'current'),
'|', '|',
('mother_grant_benefit_id', '=', relation_id),
('replacement_grant_benefit_id', '=', relation_id),
('family_member_id', '=', relation_id)
], limit=1)
if existing_current:
existing_current.education_status_type = 'previous'
return super(EducationStatus, self).create(vals)

View File

@ -0,0 +1,7 @@
from odoo import fields, models, api, _
class ExpensesType(models.Model):
_name = 'expenses.type'
name = fields.Char(string='Name', required=False)

View File

@ -0,0 +1,52 @@
from odoo import fields, models, api, _
from odoo.exceptions import UserError
class FamilyComplaints(models.Model):
_name = 'family.complaints'
_rec_name = 'complaints_reason'
_inherit = ['mail.thread', 'mail.activity.mixin']
complaints_date = fields.Datetime(string="Complaints Date",default=fields.Datetime.now)
family_id = fields.Many2one('grant.benefit',string='Family',domain="['|',('state','=','second_approve'),'&',('state','in',['waiting_approve','first_approve']),('action_type','=','suspended')]")
researcher_id = fields.Many2one("committees.line", string="Researcher",related="family_id.researcher_id")
branch_custom_id = fields.Many2one('branch.settings', string="Branch",related='family_id.branch_custom_id')
complaints_reason = fields.Char(string="Complaints Reason")
message = fields.Text(string="Message")
complaints_category_ids = fields.Many2many('complaints.category',relation="family_complaints_category_rel",
column1="family_complaints",
column2="category",
string="Complaints Categories")
priority = fields.Selection( [ ('0', 'Normal'),('1', 'Low'),('2', 'High'),('3', 'Very High'),('4', 'Very Very High'),('5', 'Danger')], string='Priority')
state = fields.Selection([('draft', 'Draft'),('receiving_complaint', 'Receiving the complaint'),('review_complaint', 'Review Complaint'),
('work_in_complaint', 'Work in complaint'),('complaint_done', 'Complaint Done'),('refuse', 'Refuse')],
default='draft',tracking=True)
def unlink(self):
for order in self:
if order.state not in ['draft']:
raise UserError(_('You cannot delete this record'))
return super(FamilyComplaints, self).unlink()
def action_receiving_complaint(self):
for rec in self:
rec.state = 'receiving_complaint'
def action_review_complaint(self):
for rec in self:
rec.state = 'review_complaint'
def action_work_in_complaint(self):
for rec in self:
rec.state = 'work_in_complaint'
def action_done(self):
for rec in self:
rec.state = 'complaint_done'
def action_refuse(self):
for rec in self:
rec.state = 'refuse'

View File

@ -0,0 +1,46 @@
from random import randint
from odoo import fields, models, api, _
class FamilyDebits(models.Model):
_name = 'family.debits'
_description = "Family - Debits"
loan_giver = fields.Many2one("loan.giver",string='Loan Giver')
loan_amount = fields.Float(string='Loan Amount')
loan_total_paid = fields.Float(string='Loan Total Paid')
loan_remaining = fields.Float(string='Loan Remaining',compute='_compute_loan_remaining',store=True)
monthly_installment = fields.Float(string='Monthly Installment')
number_of_installments = fields.Integer(string='Number of installments')
last_paid_amount = fields.Float(string='Last Paid Amount')
last_paid_amount_date = fields.Date(string='Last Paid Amount Date')
loan_start_date = fields.Date(string='Loan Start Date')
loan_end_date = fields.Date(string='Loan End Date')
loan_reason = fields.Many2one("loan.reason",string='Loan Reason')
benefit_id = fields.Many2one("grant.benefit")
currency_id = fields.Many2one('res.currency', related='benefit_id.currency_id')
loan_attach = fields.Binary(attachment=True,string='Loan Attach')
description = fields.Char(string='Description')
state = fields.Selection(string='Status', selection=[('accepted', 'Accepted'), ('refused', 'Refused')])
deduct_from_family_income = fields.Boolean(string="Deduct from Family Income")
def action_accept(self):
self.state = 'accepted'
def action_refuse(self):
self.state = 'refused'
@api.depends('loan_amount','loan_total_paid')
def _compute_loan_remaining(self):
for rec in self:
rec.loan_remaining = rec.loan_amount - rec.loan_total_paid
@api.onchange('loan_amount','number_of_installments')
def get_monthly_installment(self):
for rec in self:
if rec.loan_amount and rec.number_of_installments > 0 :
rec.monthly_installment = rec.loan_amount / rec.number_of_installments
else:
rec.monthly_installment = 0

View File

@ -0,0 +1,404 @@
# -*- coding: utf-8 -*-
from dateutil.relativedelta import relativedelta
from odoo import models, fields, api, _
from odoo.exceptions import UserError
from odoo.tools import date_utils
class ConfirmBenefitExpense(models.Model):
_name = 'confirm.benefit.expense'
_description = 'Confirm Benefit Expense'
_inherit = ['mail.thread', 'mail.activity.mixin']
_order = "family_expense_seq desc"
# region [Default Methods]
def _default_start_date(self):
today = fields.Date.today()
start_date = date_utils.start_of(today, 'month')
return start_date
def _default_end_date(self):
today = fields.Date.today()
end_date = date_utils.end_of(today, 'month')
return end_date
# endregion [Default Methods]
family_expense_seq = fields.Char(string="Number", copy=False, readonly=True,
default=lambda x: _('New'))
state = fields.Selection(selection=[
('draft', 'Draft'),
('calculated', 'Calculated'),
('assistant_general_manager', 'Waiting For The Assistant General Manager'),
('accounting_approve', 'Accounting Approve'),
('cancel', 'Cancelled'),
('confirm', 'Confirmed'),
], string='Status', default='draft', required=True, copy=False, tracking=True)
name = fields.Char(string="Name", states={'confirm': [('readonly', True)]}, copy=False)
date = fields.Date(string="Date", default=fields.Date.context_today, required=False,
states={'confirm': [('readonly', True)]})
start_date = fields.Date(string="Start Date", default=_default_start_date, required=True)
end_date = fields.Date(string="End Date", required=True, default=_default_end_date)
family_ids = fields.Many2many(comodel_name='grant.benefit', relation='benefit_expense_grant_rel',
column1='expense_id',
column2='family_id', string='Families', states={'confirm': [('readonly', True)]},
copy=False)
benefit_expense_line_ids = fields.One2many(comodel_name='benefit.expense.line', inverse_name='confirm_expense_id',
string='Benefit Expense Lines')
othaim_line_ids = fields.One2many(comodel_name='benefit.expense.line', inverse_name='confirm_expense_id',
string='Othaim Lines', domain=[('meal_card', '=', True)])
cash_expense = fields.Boolean(string='Include Cash Expense', default=True, states={'confirm': [('readonly', True)]})
meal_expense = fields.Boolean(string='Include Meal Expense', default=True, states={'confirm': [('readonly', True)]})
cloth_expense = fields.Boolean(string='Include Clothing Expense', default=True,
states={'confirm': [('readonly', True)]})
payment_order_id = fields.Many2one('payment.orders', string='Payment Order', ondelete="set null", copy=False)
move_id = fields.Many2one('account.move', ondelete='cascade')
available_payment_method_line_ids = fields.Many2many(comodel_name='account.payment.method.line')
family_monthly_income = fields.Float(string="Total Monthly Income", compute='_get_family_monthly_values',
store=True)
family_monthly_meals = fields.Float(string="Total Monthly Meals", compute='_get_family_monthly_values', store=True)
family_monthly_clotting = fields.Float(string="Total Monthly Clotting", compute='_get_family_monthly_values',
store=True)
family_monthly_othaime = fields.Float(string="Total Othaim", compute='_get_family_monthly_values', store=True)
family_monthly_total = fields.Float(string="Total", compute='_get_family_monthly_values', store=True)
branch_custom_ids = fields.Many2many(comodel_name='branch.settings', relation='confirm_benefit_expense_branch_rel',
column1='expense_id', column2='branch_id', string="Branches",
domain="[('has_employees', '=', True)]")
family_domain_ids = fields.Many2many(comodel_name='grant.benefit', compute='_compute_domain_ids')
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')
payment_state = fields.Selection(string='Payment State', selection=[
('none', 'None'),
('waiting', 'Waiting Payment'),
('done', 'Done Payment'), ], copy=False, compute="_compute_payment_move_state", store=True)
move_state = fields.Selection(string='Move State', selection=[
('none', 'None'),
('waiting', 'Waiting Payment'),
('done', 'Done Payment'), ], copy=False, compute="_compute_payment_move_state", store=True)
family_count_expense = fields.Integer(string="Family Count (Monthly Expense)",
compute='_get_family_monthly_values', store=True)
family_count_othaim = fields.Integer(string="Family Count (Othaim)", compute='_get_family_monthly_values',
store=True)
member_count_expense = fields.Integer(string="Member Count (Monthly Expense)", compute='_get_family_monthly_values',
store=True, )
member_count_othaim = fields.Integer(string="Member Count (Othaim)", compute='_get_family_monthly_values',
store=True, )
is_return_calculation = fields.Boolean(string="Return Calculation Mode", default=False,
help="Enable to calculate returned amounts instead of regular monthly expense."
)
return_expense_line_ids = fields.One2many(comodel_name='benefit.expense.line', inverse_name='return_confirm_id',
string="Selected Return Lines",
domain="[('is_return', '=', True)]", )
line_domain_ids = fields.Many2many(comodel_name='benefit.expense.line', compute='_compute_domain_ids',
string="Return Line Domain",
)
@api.depends('payment_order_id', 'payment_order_id.state', 'move_id', 'move_id.state')
def _compute_payment_move_state(self):
for rec in self:
payment_state = 'none'
move_state = 'none'
if rec.payment_order_id:
if rec.payment_order_id.state == "done":
payment_state = "done"
else:
payment_state = "waiting"
if rec.move_id:
if rec.move_id.state == "posted":
move_state = "done"
else:
move_state = "waiting"
rec.move_state = move_state
rec.payment_state = payment_state
if rec.move_state == 'done' and rec.payment_state == 'done':
rec.state = 'confirm'
@api.model
def create(self, vals):
res = super(ConfirmBenefitExpense, self).create(vals)
if not res.family_ids:
raise UserError(_('Select Family'))
if not res.family_expense_seq or res.family_expense_seq == _('New'):
res.family_expense_seq = self.env['ir.sequence'].sudo().next_by_code('family.expense.sequence') or _('New')
return res
def _update_benefit_expense_lines(self):
self.ensure_one()
for line in self.benefit_expense_line_ids:
family = line.family_id
income, meals, clotting, othaim = 0, 0, 0, 0
if not family:
continue
monthly_meals = 0.0 if family.meal_card else family.family_monthly_meals
othaime = family.family_monthly_meals if family.meal_card else 0.0
if self.cash_expense:
income = family.family_monthly_income
if self.meal_expense:
meals = monthly_meals
othaim = othaime
if self.cloth_expense:
clotting = family.family_monthly_clotting
vals = {
'branch_id': family.branch_custom_id.id,
'family_category_id': family.benefit_category_id.id,
'meal_card': family.meal_card,
'benefit_member_count': family.benefit_member_count,
'start_date': self.start_date,
'end_date': self.end_date,
'family_monthly_income': income,
'family_monthly_meals': meals,
'family_monthly_clotting': clotting,
'family_monthly_othaime': othaim,
}
line.write(vals)
def _calculate_return_lines(self):
self.ensure_one()
return_lines = self.return_expense_line_ids
if not return_lines:
raise UserError(_("Please select at least one return line to calculate."))
lines = []
for line in return_lines:
lines.append((0, 0, {
'family_id': line.family_id.id,
'branch_id': line.branch_id.id,
'family_category_id': line.family_category_id.id,
'meal_card': line.meal_card,
'benefit_member_count': line.benefit_member_count,
'start_date': self.start_date,
'end_date': self.end_date,
'family_monthly_income': line.family_monthly_income,
'family_monthly_meals': line.family_monthly_meals,
'family_monthly_clotting': line.family_monthly_clotting,
'family_monthly_othaime': 0,
}))
self.benefit_expense_line_ids = lines
def action_calculate(self):
for rec in self:
if rec.state != 'draft':
raise UserError(_("You can only calculate in draft state."))
families = rec.family_ids
if not families:
raise UserError(_("Please select at least one family to calculate."))
if not rec.cash_expense and not rec.meal_expense and not rec.cloth_expense:
raise UserError(_("At least one expense type should be selected."))
if rec.is_return_calculation:
rec._calculate_return_lines()
else:
rec.benefit_expense_line_ids.unlink()
lines = []
for fam in families:
vals = {
'confirm_expense_id': rec.id,
'family_id': fam.id,
'start_date': rec.start_date,
'end_date': rec.end_date,
}
lines.append((0, 0, vals))
rec.write({'benefit_expense_line_ids': lines})
rec._update_benefit_expense_lines()
rec.state = 'calculated'
def action_recalculate(self):
for rec in self:
if rec.state != 'calculated':
raise UserError(_("You can only recalculate when status is 'Calculated'."))
rec._update_benefit_expense_lines()
@api.depends('is_return_calculation', 'branch_custom_ids', 'start_date', 'end_date')
def _compute_domain_ids(self):
for rec in self:
Line = self.env['benefit.expense.line']
validation_setting = self.env["family.validation.setting"].search([], limit=1)
if rec.is_return_calculation:
domain = [
('start_date', '<=', rec.end_date),
('end_date', '>=', rec.start_date),
('is_return', '=', True),
('return_reason_id', '!=', False),
('return_confirm_id', '=', False),
]
if rec.branch_custom_ids:
domain.append(('branch_id', 'in', rec.branch_custom_ids.ids))
return_lines = Line.search(domain)
rec.line_domain_ids = return_lines
rec.family_domain_ids = return_lines.mapped('family_id')
else:
# Define base domain for family selection
base_domain = ['|', ('state', '=', 'second_approve'), '&',
('state', 'in', ('waiting_approve', 'first_approve')), ('action_type', '=', 'suspended')]
if rec.branch_custom_ids:
base_domain.append(('branch_custom_id', 'in', rec.branch_custom_ids.ids))
min_income = validation_setting.benefit_category_ids.mapped('mini_income_amount')
max_income = validation_setting.benefit_category_ids.mapped('max_income_amount')
base_domain.extend([('member_income', '>=', min(min_income)), ('member_income', '<=', max(max_income))])
base_domain.extend([('benefit_category_id', '!=', False)])
if rec.start_date and rec.end_date:
conflicting_records = self.search([
('id', '!=', rec._origin.id),
('start_date', '<=', rec.end_date),
('end_date', '>=', rec.start_date),
])
if conflicting_records:
conflicting_family_ids = conflicting_records.mapped('family_ids').ids
base_domain.append(('id', 'not in', conflicting_family_ids))
rec.family_domain_ids = self.env['grant.benefit'].search(base_domain)
rec.line_domain_ids = self.env['benefit.expense.line'].browse([])
@api.onchange('branch_custom_ids')
def _onchange_branch_custom_ids(self):
if self.branch_custom_ids:
allowed_families = self.env['grant.benefit'].search([
('id', 'in', self.family_ids.ids),
('branch_custom_id', 'in', self.branch_custom_ids.ids),
])
self.family_ids = [(6, 0, allowed_families.ids)]
else:
self.family_ids = [(5, 0, 0)]
def unlink(self):
for rec in self:
if rec.state not in ['draft']:
raise UserError(_('This record can only be deleted in draft state.'))
return super(ConfirmBenefitExpense, self).unlink()
@api.depends('benefit_expense_line_ids')
def _get_family_monthly_values(self):
for rec in self:
lines = rec.benefit_expense_line_ids
rec.family_monthly_income = sum(lines.mapped('family_monthly_income'))
rec.family_monthly_meals = sum(lines.mapped('family_monthly_meals'))
rec.family_monthly_clotting = sum(lines.mapped('family_monthly_clotting'))
rec.family_monthly_othaime = sum(lines.mapped('family_monthly_othaime'))
rec.family_monthly_total = rec.family_monthly_income + rec.family_monthly_meals + rec.family_monthly_clotting
expense_lines = lines.filtered(lambda l: not l.meal_card)
othaim_lines = lines.filtered('meal_card')
rec.family_count_expense = len(expense_lines.mapped('family_id'))
rec.member_count_expense = sum(expense_lines.mapped('benefit_member_count'))
rec.family_count_othaim = len(othaim_lines.mapped('family_id'))
rec.member_count_othaim = sum(othaim_lines.mapped('benefit_member_count'))
def action_assistant_manager(self):
for family in self.family_ids:
if self.end_date and family.last_disbursement_date:
if self.end_date > family.last_disbursement_date:
family.last_disbursement_date = self.end_date
else:
family.last_disbursement_date = self.end_date
self.state = 'assistant_general_manager'
def action_accounting_approve(self):
self.state = 'accounting_approve'
def action_cancel(self):
self.state = 'cancel'
def action_reset_to_draft(self):
self.payment_order_id.unlink()
self.move_id.unlink()
self.benefit_expense_line_ids.unlink()
self.state = 'draft'
def action_open_related_move_records(self):
moves = self.move_id.ids
return {
'name': _('Vendor Bills'),
'type': 'ir.actions.act_window',
'res_model': 'account.move',
'view_mode': 'tree,form',
'domain': [('id', 'in', moves)],
}
def action_open_related_payment_orders(self):
payment_orders = self.payment_order_id.ids
return {
'name': _('Payment Orders'),
'type': 'ir.actions.act_window',
'res_model': 'payment.orders',
'view_mode': 'tree,form',
'domain': [('id', 'in', payment_orders)],
}
def action_accounting_transfer(self):
for rec in self:
validation_setting = self.env["family.validation.setting"].search([], limit=1)
lines = rec.benefit_expense_line_ids
if not lines:
raise UserError(_("Please make sure you have benefit expense lines."))
families = lines.mapped('family_id')
invalid_families = families.filtered(
lambda f: f.state != 'second_approve'
or (f.state in ('waiting_approve', 'first_approve') and f.action_type == 'suspended')
)
if invalid_families:
raise UserError(_(
"Some selected benefits are not in valid state or are suspended:\n%s"
) % ", ".join(invalid_families.mapped('name')))
if not validation_setting.cash_expense_account_id or not validation_setting.meal_expense_account_id or not validation_setting.clothing_expense_account_id:
raise UserError(_("Please configure the expense accounts in the validation settings."))
credit_account_id = validation_setting.account_id.id
if not credit_account_id:
raise UserError(_("Please select credit account."))
# todo if have paymnet or move dont create again
# Create Payment Order for Benefit Expense
payment_order = self.env['payment.orders'].create({
'state': 'draft',
'accountant_id': validation_setting.accountant_id.id,
'benefit_expense_line_ids': [(6, 0, rec.benefit_expense_line_ids.ids)],
'type': 'benefit_expense',
})
rec.payment_order_id = payment_order
if not rec.is_return_calculation:
# Create Vendor Bill for Meal Card Invoice(othaime)
account_id = validation_setting.meal_expense_account_id
invoice_lines = []
for line in lines.filtered(lambda l: l.meal_card):
family = line.family_id
invoice_lines.append((0, 0, {
'name': f'{family.name}/{family.code}',
'account_id': account_id.id,
'quantity': 1,
'benefit_family_id': family.id,
'price_unit': line.family_monthly_othaime,
'analytic_account_id': family.branch_family_id.branch.analytic_account_id.id
}))
invoice_vals = {
'move_type': 'in_invoice',
'partner_id': validation_setting.meal_partner_id.id,
'invoice_date': rec.date,
'family_confirm_id': rec.id,
'benefit_family_ids': [(6, 0, rec.benefit_expense_line_ids.mapped('family_id').ids)],
'journal_id': validation_setting.journal_id.id,
'invoice_line_ids': invoice_lines,
'ref': rec.name,
}
invoice = self.env['account.move'].create(invoice_vals)
rec.move_id = invoice
return True

View File

@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
from dateutil.relativedelta import relativedelta
from odoo import models, fields, api, _
from odoo.exceptions import UserError
from odoo.tools import date_utils
class BenefitExpenseLine(models.Model):
_name = 'benefit.expense.line'
_description = 'Benefit Expense Line'
_inherit = ['mail.thread', 'mail.activity.mixin']
confirm_expense_id = fields.Many2one(comodel_name='confirm.benefit.expense', string='Confirm Benefit Expense',
ondelete='cascade')
return_confirm_id = fields.Many2one('confirm.benefit.expense', string="Return Confirm", ondelete="set null", )
family_id = fields.Many2one(comodel_name='grant.benefit', string='Family', required=True)
branch_id = fields.Many2one(comodel_name='branch.settings', string='Branch')
family_category_id = fields.Many2one(comodel_name='benefit.category', string='Family Category')
meal_card = fields.Boolean(string="Meal Card")
benefit_member_count = fields.Integer(string="Members count")
family_monthly_income = fields.Float(string="Family Monthly Income")
family_monthly_meals = fields.Float(string="Family Monthly Meals")
family_monthly_clotting = fields.Float(string="Family Monthly Clotting")
family_monthly_othaime = fields.Float(string="Othaim Total Monthly")
total_family_expenses = fields.Float(string="Total Family Expenses", compute='_compute_total_family_expenses')
start_date = fields.Date(string='Start Date', )
end_date = fields.Date(string='End Date', )
payment_order_id = fields.Many2one('payment.orders', string='Payment Order', ondelete="set null", copy=False)
return_reason_id = fields.Many2one("return.reason", string="Return Reason")
is_return = fields.Boolean(string="Is Returned?", default=False)
@api.depends('family_monthly_income', 'family_monthly_clotting', 'family_monthly_meals')
def _compute_total_family_expenses(self):
for rec in self:
rec.total_family_expenses = rec.family_monthly_income + rec.family_monthly_meals + rec.family_monthly_clotting
def action_return_bank(self):
self.ensure_one()
return {
'name': _("Bank Return"),
'type': 'ir.actions.act_window',
'res_model': 'return.reason.wizard',
'view_mode': 'form',
'target': 'new',
'context': {
'default_line_id': self.id,
'default_line_model': 'benefit.expense.line',
}
}

View File

@ -0,0 +1,14 @@
from odoo import fields, models,api
class FamilyMemberExam(models.Model):
_name = 'family.member.exam'
_description = 'Family Member Exam'
_order = 'id desc'
member_id = fields.Many2one('family.member', string='Family Member')
exam_id = fields.Many2one('education.exam.type', string='Exam Type', required=True)
exam_degree = fields.Float(string='Exam Degree')
exam_date = fields.Date(string='Exam Date')
exam_attachment = fields.Binary(string='Exam Attachment', attachment=True)
exam_attachment_file_name = fields.Char(required=False)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
from odoo import fields, models, api, _
from odoo.exceptions import ValidationError
class FamilyValidationSetting(models.Model):
_name = 'family.validation.setting'
female_benefit_age = fields.Integer(string='Female Benefit Age')
male_benefit_age = fields.Integer(string='Male Benefit Age')
exceptional_age_scientific_specialty = fields.Integer(string='Exceptional Age Scientific Specialty')
exceptional_age_medical_specialty = fields.Integer(string='Exceptional Age Medical Specialty')
exceptional_age_has_disabilities = fields.Integer(string='Exceptional Age Has Disabilities')
max_income_for_benefit = fields.Float(string='Max Income Benefit')
mini_income_for_mother = fields.Float(string='Min Income Mother')
max_income_for_mother = fields.Float(string='Max Income Mother')
minor_siblings_age = fields.Integer(string='Minor Siblings Age')
cash_expense = fields.Float(string='Cash Expense')
cash_expense_account_id = fields.Many2one('account.account', string='Cash Expense Account',
domain=[('deprecated', '=', False), ('internal_type', '=', 'other')])
meal_expense = fields.Float(string='Meal Expense')
meal_expense_account_id = fields.Many2one('account.account', string='Meal Expense Account',
domain=[('deprecated', '=', False), ('internal_type', '=', 'other')])
clothing_expense = fields.Float(string='Clothing Expense')
clothing_expense_account_id = fields.Many2one('account.account', string='Clothing Expense Account',
domain=[('deprecated', '=', False), ('internal_type', '=', 'other')])
benefit_category_ids = fields.Many2many(comodel_name='benefit.category',
relation='benefit_category_family_validation_rel',
column1='family_id', column2='categ_id', string='Benefit Categories')
meal_partner_id = fields.Many2one('res.partner', string='Meal Partner')
journal_id = fields.Many2one('account.journal', string='Journal')
payment_journal_id = fields.Many2one('account.journal', string='Payment Journal' , domain="[('type', 'in', ['cash', 'bank'])]")
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')
def _constraint_amount_should_be_positive_if_account_selected(self):
for rec in self:
if rec.meal_expense_account_id:
if rec.meal_expense <= 0:
raise ValidationError(_('Meal Expense should be positive if meal account selected'))
if rec.clothing_expense_account_id:
if rec.clothing_expense <= 0:
raise ValidationError(_('Clothing Expense should be positive if clothing account selected'))
if rec.cash_expense_account_id:
if rec.cash_expense <= 0:
raise ValidationError(_('Cash Expense should be positive if cash account selected'))

View File

@ -0,0 +1,447 @@
import base64
import datetime
from odoo import fields, models, api, _
from odoo.exceptions import ValidationError, UserError
class ReportLog(models.Model):
_name = 'generate.reports.log'
_description = 'Reports log'
name = fields.Char()
datetime = fields.Datetime()
user_id = fields.Many2one('res.users')
attach = fields.Binary(string="", )
class GenerateReports(models.TransientModel):
_name = 'generate.reports'
_description = 'Generate Reports For Benefits'
name = fields.Char()
current_user = fields.Many2one('res.users', 'Current User', default=lambda self: self.env.user)
service_to = fields.Selection(
selection=[('benefit', 'Benefit'), # 1
('family', 'Family'), # 2
('house', 'House')]) # 3
service_category = fields.Selection(
string='', selection=[('financial', 'financial'),
('In-kind', 'In-kind'),
('seasonal', 'seasonal'), ])
house_service_category = fields.Selection(
string='', selection=[('financial', 'financial'),
('In-kind', 'In-kind'),
('fittings', 'fittings'),
('car_need', 'car need'),
])
benefit_service_category = fields.Selection(
string='', selection=[('financial', 'financial'),
('In-kind', 'In-kind'),
('teaching', 'teaching'),
('qualification', 'qualification'),
('training', 'training'),
('omra', 'omra'),
])
seasonal_service_type = fields.Selection(
string='', selection=[
('zkat', 'zkat alfeter'),
('sacrifice', 'sacrifice')
])
service_type = fields.Selection(
string='', selection=[
('urgent', 'urgent'),
('non-urgent', 'non-urgent'),
])
# position = fields.Selection(string="Position",
# selection=service_to_benefit + service_to_benefit,
# compute='calculation_list', store=True)
# service_to_benefit = fields.Selection(string='Company Position', selection=service_to_benefit)
housing_financial_type = fields.Selection(
string='', selection=[
('rent', 'rent amount'),
('maintenance', 'maintenance expenses'),
('expenses', 'All expenses'),
])
qualification_type = fields.Selection(
string='', selection=[
('fat', 'fat'),
('behavior', 'behavior'),
])
teaching_type = fields.Selection(
string='', selection=[
('literacy', 'Literacy'),
('memorization', 'memorization'),
('specialty', 'specialty'),
])
report_file = fields.Binary(string="", )
education_status = fields.Selection(string='Education Status',
selection=[('educated', 'educated'), ('illiterate', 'illiterate')])
case_study = fields.Selection(string='Education Status', selection=[('continuous', 'continuous'),
('intermittent', 'intermittent')])
category_id = fields.Many2many('benefit.category')
date = fields.Datetime(string='Date', default=fields.Datetime.now)
date_from = fields.Datetime()
date_to = fields.Datetime()
club_programs = fields.Many2one('benefit.programs', string='')
age_from = fields.Integer()
age_to = fields.Integer()
max_rent = fields.Integer()
family_id = fields.Many2many('benefit.family','benefit_family_group_rel','generate_id','benefit_id')
benefit_id = fields.Many2many('grant.benefit')
housing_id = fields.Many2many('benefit.housing')
housing_room_ids = fields.Many2many('housing.rooms.members')
housing_rent_ids = fields.Many2many('housing.need')
specialization_id = fields.Many2one('specialization.specialization')
product_id = fields.Many2one('product.product')
appliances_furniture_need = fields.Many2many('appliances.furniture.need')
# appliances_furniture_need = fields.Many2many('benefit.housing.rooms')
behavior_id = fields.Many2one('benefit.behaviors.type')
training_type_id = fields.Many2one('training.type')
percentage = fields.Float()
benefit_ids = fields.Many2many('grant.benefit', 'benefits', 'id_number', 'birth_date')
benefit_f_needs_percent = fields.Many2many('grant.benefit', 'financial', 'id_number', 'birth_date')
benefit_qualification_ids = fields.Many2many('grant.benefit', 'qualification', 'id_number', 'birth_date')
benefit_teaching_ids = fields.Many2many('grant.benefit', 'teaching', 'id_number', 'specialization_ids')
benefit_training_ids = fields.Many2many('grant.benefit', 'training', 'id_number', 'specialization_ids')
benefit_omra_ids = fields.Many2many('grant.benefit', 'benefits_omra', 'age', 'amra_date')
black_list = fields.Many2many('grant.benefit', 'black_list', 'id_number', 'is_zakat_fitr')
housing_need_car_ids = fields.Many2many('benefit.housing', 'cars', 'name', 'benefit_ids')
benefits_need_ids = fields.Many2many('benefits.needs')
family_need_ids = fields.Many2many('benefit.family')
description = fields.Char()
fat = fields.Float(default=30.0)
@api.onchange('service_to', 'service_type', 'benefit_service_category', 'house_service_category',
'service_category', 'behavior_id', 'seasonal_service_type',
'product_id', 'qualification_type',
'teaching_type', 'housing_financial_type', 'behavior_id')
def calculation(self):
domain = []
domain += [('age', '>=', self.age_from), ('age', '<=', self.age_to if self.age_to != 0 else 3000)]
if self.service_to == 'benefit': # 1
# 1
if self.benefit_service_category == 'financial':
ids = []
benefits_f_need = self.env['grant.benefit'].sudo().search([])
for i in benefits_f_need:
if i.benefit_needs_percent >= self.percentage:
ids.append(i.id)
self.benefit_f_needs_percent = ids
# 2
if self.benefit_service_category == 'In-kind' and self.product_id:
if self.service_type == 'urgent':
benefits_need = self.env['benefits.needs'].sudo().search(
[('state', 'in', ['approve', 'published']), ('need_status', '=', 'urgent'),
('need_type_ids', 'in', self.product_id.id)])
if self.service_type == 'non-urgent':
benefits_need = self.env['benefits.needs'].sudo().search(
[('state', 'in', ['approve', 'published']), ('need_status', '=', 'not_urgent'),
('need_type_ids', 'in', self.product_id.id)])
if self.service_type:
self.benefits_need_ids = [(6, 0, benefits_need.ids)]
# 3
if self.benefit_service_category == 'omra': # B
benefits = self.env['grant.benefit'].sudo().search(domain)
self.benefit_omra_ids = [(6, 0, benefits.ids)]
# 4
if self.benefit_service_category == 'qualification': # 2
if self.qualification_type == 'behavior':
benefits_list = []
benefits = self.env['grant.benefit'].sudo().search(domain)
for i in benefits:
for x in i.benefit_behavior_ids:
if self.behavior_id.id == x.behavior_id.id:
benefits_list.append(i.id)
self.benefit_qualification_ids = [(6, 0, benefits_list)]
if self.qualification_type == 'fat': # 5
domain += [('p_weight', '>', self.fat)]
benefits = self.env['grant.benefit'].sudo().search(domain)
self.benefit_qualification_ids = [(6, 0, benefits.ids)]
# 5
if self.benefit_service_category == 'teaching': # 5
if self.teaching_type == 'literacy':
domain += [('education_status', '=', 'illiterate')]
benefits = self.env['grant.benefit'].sudo().search(domain)
# self.benefit_teaching_ids = [(6, 0, benefits.ids)]
if self.teaching_type == 'memorization':
domain += [('is_quran_memorize', '=', True)]
benefits = self.env['grant.benefit'].sudo().search(domain)
# self.benefit_teaching_ids = [(6, 0, benefits.ids)]
if self.teaching_type == 'specialty':
domain += [('specialization_ids', '=', self.specialization_id.id)]
benefits = self.env['grant.benefit'].sudo().search(domain)
if self.teaching_type:
self.benefit_teaching_ids = [(6, 0, benefits.ids)]
# 6
if self.benefit_service_category == 'teaching': # 5
if self.training_type_id:
self.benefit_teaching_ids = [(6, 0, benefits.ids)]
if self.service_to == 'family': # 2
if self.service_category == 'financial':
ids = []
benefit_family = self.env['benefit.family'].sudo().search([])
for i in benefit_family:
if i.benefit_needs_percent >= self.percentage:
ids.append(i.id)
self.family_need_ids = ids
# 2
if self.service_category == 'seasonal' and self.seasonal_service_type == 'zkat':
benefits = self.env['grant.benefit'].sudo().search([])
black_list = self.env['grant.benefit'].sudo().search([('is_zakat_fitr', '=', False)])
self.black_list = [(6, 0, black_list.ids)]
benefits_list = []
for i in benefits:
benefits_list.append(i.id)
for i in black_list:
if i.id in benefits_list:
if i.id in self.black_list.ids:
benefits_list.remove(i.id)
self.benefit_ids = [(6, 0, benefits_list)]
if self.service_to == 'house': # 3
if self.house_service_category == 'In-kind' and self.product_id:
for rec in self:
rooms = rec.env['benefit.housing.rooms'].sudo().search(
[('items.item.name', '=', rec.product_id.name)])
room_list = []
need_list = []
for room in rooms:
needs = {}
needs["ap_id"] = self._origin.id
needs["housing_id"] = room.housing_id.id
needs["room_id"] = room.id
for test in room.items:
if test.item.name == rec.product_id.name:
if test.percentage >= self.percentage:
needs["percentage"] = test.percentage
needs["status"] = test.status.id
needs["name"] = test.item.name
room_list.append(room.housing_id.id)
need_list.append(needs)
if rooms:
benefit = []
for room in rooms:
benefits = rec.env['grant.benefit'].sudo().search(
[('housing_id', '=', room.housing_id.id), ('benefit_type', '=', 'benefit')])
for i in benefits:
benefit.append(i.id)
for r in rec:
r.benefit_ids = [(6, 0, benefit)]
for ap in self.appliances_furniture_need:
for i in range(len(need_list)):
if need_list[i]['housing_id'] == ap.housing_id:
del need_list[i]
break
if not self.appliances_furniture_need:
for need_item in need_list:
self.appliances_furniture_need = [(0, 0, need_item)]
if self.house_service_category == 'financial' and self.housing_financial_type == 'rent': # 3
for rec in self:
self.housing_rent_ids = False
housing = rec.env['benefit.housing'].sudo().search([('rent_amount', '>=', rec.max_rent)])
need_list = []
for i in housing:
needs = {}
needs["ap_id"] = self._origin.id
needs["housing_id"] = i.id
# needs["benefit_id"] = room.housing_id.id
needs["amount"] = i.rent_amount
need_list.append(needs)
self.housing_rent_ids = [(0, 0, needs)]
if self.house_service_category == 'fittings':
for rec in self:
rooms = rec.env['housing.rooms.members'].sudo().search(
[('is_accept', '!=', True)])
self.housing_room_ids = rooms.ids
if self.house_service_category == 'car_need':
benefits = self.env['grant.benefit'].sudo().search([])
ids = []
for rec in benefits:
if rec.car_count == 0:
ids.append(rec.id)
housing = rec.env['benefit.housing'].sudo().search([('benefit_ids', 'in', ids)])
self.housing_need_car_ids = housing.ids
@api.onchange('black_list')
def calculation_2(self):
if self.service_to == 'family' and self.service_category == 'seasonal' and self.service_type == 'zkat':
black_list = self.env['grant.benefit'].sudo().search([('is_zakat_fitr', '=', False)])
benefits_list = []
for i in black_list:
if i.id not in self.black_list.ids:
benefits_list.append(i.id)
for x in benefits_list:
self.benefit_ids = [(4, x)]
@api.onchange('benefit_ids')
def calculation_3(self):
if self.service_to == 'family' and self.service_category == 'seasonal' and self.service_type == 'zkat':
benefit = self.env['grant.benefit'].sudo().search([])
black_list = []
for i in benefit:
if i.id not in self.benefit_ids.ids:
black_list.append(i.id)
for x in black_list:
self.black_list = [(4, x)]
def get_result(self):
# if self.service_to == 'family' and self.service_category == 'In-kind' and self.service_type == 'zkat':
benefits_family = {}
list = []
for i in self.benefit_ids:
dic = {}
dic["family_id"] = i.family_id.id
count = 0
for x in self.benefit_ids:
if x.family_id.id == dic["family_id"]:
count += 1
dic["benefits_total"] = count
if dic not in list:
list.append(dic)
benefit_zkat = self.env['benefit.zkat'].sudo().create({'name': self.name, })
for i in list:
benefit_zkat.sudo().write({'zkat_ids': [(0, 0, i)]})
def create_club(self):
programs = self.env['benefit.programs'].sudo().search([('behaviors_programs', 'in', self.behavior_id.id)])
benefit_club = self.env['benefit.club'].sudo().create({'name': self.name, 'benefit_type': 'internal', })
benefit_club.benefit_programs = programs
benefit_club.benefit_ids = self.benefit_qualification_ids
def get_need(self):
if self.service_to == 'benefit' and self.benefit_service_category == 'financial':
ids = self.benefit_f_needs_percent.ids
needs_value = 0.0
for i in self.benefit_f_needs_percent:
needs_value += i.benefit_needs_value
benefit_need_type = ''
if ids and len(ids) > 1:
benefit_need_type = 'general'
elif ids and len(ids) == 1:
benefit_need_type = 'special'
benefit_needs = self.env['benefits.needs'].sudo().create({
'name': self.name,
'benefit_need_type': benefit_need_type,
'date': datetime.datetime.now(),
'benefit_id': ids[0] if len(ids) == 1 else '',
'benefit_ids': [(6, 0, ids)] if len(ids) > 1 else [],
'f_amount': needs_value,
'state': 'sent',
'need_type_ids': [(4, self.product_id.id)] if self.product_id.id else []
})
def get_rent(self):
pass
# @api.multi
def print_report(self):
benefits = []
needs = []
family = []
rooms = []
columns_ar_headers = []
columns_headers = []
if self.service_to == 'benefit':
if self.benefit_service_category == 'financial':
columns_ar_headers = ['الاسم', 'العائلة', 'مبلغ الاحتياج', 'نسبة الاحتياج']
columns_headers = ['name', 'family_id', 'benefit_needs_value', 'benefit_needs_percent']
for i in self.benefit_f_needs_percent:
benefits.append(i.id)
if self.benefit_service_category == 'In-kind':
columns_ar_headers = ['الاسم', 'نوع الاحتياج', 'التاريخ', 'نوع المستفيدين', 'حالة الاحتياج', 'الهدف',
'نسبة الاكمال', 'المستفيدين']
columns_headers = ['name', 'benefit_need_type', 'date', 'benefit_type', 'need_status', 'target_amount',
'completion_ratio', 'benefit_ids']
for i in self.benefits_need_ids:
needs.append(i.id)
if self.benefit_service_category == 'teaching':
if self.teaching_type == 'memorization':
columns_ar_headers = ['الاسم', 'العائلة', 'حافظ للقران']
columns_headers = ['name', 'family_id', 'is_quran_memorize']
if self.teaching_type == 'specialty':
columns_ar_headers = ['الاسم', 'العائلة', 'التخصص']
columns_headers = ['name', 'family_id', 'specialization_ids']
for i in self.benefit_teaching_ids:
benefits.append(i.id)
if self.benefit_service_category == 'qualification':
if self.qualification_type == 'behavior':
columns_ar_headers = ['الاسم', 'النوع', 'العمر', 'السلوك']
columns_headers = ['name', 'gender', 'age', 'benefit_behavior_ids']
if self.qualification_type == 'fat':
columns_ar_headers = ['الاسم', 'النوع', 'العمر', 'نسبة الدهون']
columns_headers = ['name', 'gender', 'age', 'p_weight']
for i in self.benefit_qualification_ids:
benefits.append(i.id)
if self.benefit_service_category == 'training':
columns_ar_headers = ['الاسم', 'النوع', 'العمر', 'التدريب', 'السلوك']
columns_headers = ['name', 'gender', 'age', 'p_weight', 'benefit_behavior_ids']
if self.benefit_service_category == 'omra':
columns_ar_headers = ['الاسم', 'النوع', 'العمر', 'تاريخ اخر عمرة']
columns_headers = ['name', 'gender', 'age', 'amra_date']
for i in self.benefit_omra_ids:
benefits.append(i.id)
if self.service_to == 'family':
if self.service_category == 'financial':
columns_ar_headers = ['الاسم', 'عدد المستفيدين', 'العائل', 'منتجة ام لا ', 'مجموع الدخل',
'مجموع المصروفات']
columns_headers = ['name', 'benefits_total', 'responsible_benefit_id', 'is_producer', 'total_income',
'total_expenses']
for i in self.family_need_ids:
family.append(i.id)
if self.service_category == 'seasonal' and self.seasonal_service_type == 'zkat':
columns_ar_headers = ['الاسم', 'النوع', 'العمر', 'العائلة']
columns_headers = ['name', 'gender', 'age', 'family_id']
for i in self.benefit_ids:
benefits.append(i.id)
if self.service_to == 'house':
if self.house_service_category == 'fittings':
columns_ar_headers = ['الوحدة السكنية', 'الغرفة', 'نوع الغرفة', 'المستفيد', 'العمر', 'النوع']
columns_headers = ['housing_id', 'room_id', 'rooms_categories_id', 'benefit_id', 'age', 'gender']
for i in self.housing_room_ids:
rooms.append(i.id)
if benefits != [] or needs != [] or family != [] or rooms != [] or columns_ar_headers != [] or columns_headers != []:
length = len(columns_headers)
data = {'age_from': self.age_from, 'age_to': self.age_to, 'name': self.name, 'benefits': benefits,
'needs': needs,
'family': family,
'rooms': rooms,
'ar_headers': columns_ar_headers,
'length': length,
'header': columns_headers, }
pdf = self.env.ref('odex_benefit.generate_benefit_report_pdf')._render_qweb_pdf(self, data=data)
# b64_pdf = base64.b64encode(pdf[0])
b64_pdf = base64.b64encode(pdf[0]).decode("ascii")
# save pdf as attachment
ir = self.env['ir.attachment'].create({
'name': self.name if self.name else '' + '.pdf',
'type': 'binary',
'datas': b64_pdf,
# 'datas_fname': self.name + '.pdf',
'store_fname': self.name,
'res_model': self._name,
'res_id': self.id,
'mimetype': 'application/pdf'
})
self.env['generate.reports.log'].create({
'name': self.name,
'user_id': self.current_user.id,
'datetime': datetime.datetime.now(),
'attach': b64_pdf
})
self.report_file = b64_pdf
return {'type': 'ir.actions.report', 'report_name': 'odex_benefit.template_generate_benefit_report_pdf',
'report_type': "qweb-pdf", 'data': data, }
else:
raise ValidationError(_("Sorry, there are no results for this selection !"))
def rest(self):
return {
'name': _('Generate Reports'),
'view_mode': 'form',
'view_type': 'form',
'type': 'ir.actions.act_window',
'res_model': 'generate.reports',
'view_id': self.env.ref('odex_benefit.generate_reports_view_form').id,
'target': 'new',
}

View File

@ -0,0 +1,428 @@
from random import randint
from odoo import fields, models, api, _
class City(models.Model):
_name = 'res.country.city'
_description = "Benefits - City"
@api.depends('code', 'name')
def _load_country_id(self):
for r in self:
r.country_id = self.env.ref('base.sa')
code = fields.Char(string='Code')
name = fields.Char(string='Name')
state_id = fields.Many2one('res.country.state', string='State')
country_id = fields.Many2one('res.country', string='Country', compute='_load_country_id', store=True, readonly=False)
active = fields.Boolean(default=True)
class housing(models.Model):
_name = 'benefit.housing'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = "Benefits - housing"
name = fields.Char(compute='_compute_get_name')
city_id = fields.Many2one('res.country.city', string='City')
block = fields.Char(string='block')
street = fields.Char(string='street')
url = fields.Char(compute="open_map")
url_html = fields.Html(
sanitize=False,
compute="get_html")
lat = fields.Char()
lon = fields.Char()
house_number = fields.Char(string='house number')
floor = fields.Char(string='floor')
housing_number = fields.Char(string='housing number')
image = fields.Binary(string="", )
image_1 = fields.Binary(string="", )
image_2 = fields.Binary(string="", )
image_3 = fields.Binary(string="", )
image_4 = fields.Binary(string="", )
nearby_mosque = fields.Char(string='Nearby mosque')
housing_note = fields.Char(string='housing note')
note_neighborhood = fields.Char()
rent_amount = fields.Integer()
housing_type = fields.Selection([
('apartment', 'apartment'),
('villa', 'villa'),
('popular_house', 'popular house'),
('tent', 'tent'),
('Appendix', 'Appendix'), ], default='apartment')
housing_cat = fields.Selection([
('excellent', 'Excellent'),
('good', 'Good'),
('bad', 'Bad'),
('collapsible', 'Collapsible'),
('collapsed', 'Collapsed')])
property_type = fields.Selection([
('ownership', 'ownership'),
('rent', 'rent'),
('charitable', 'charitable'),
('ownership_shared', 'Ownership Shared'),
('rent_shared', 'Rent Shared')])
rooms_number = fields.Integer('Rooms Number', compute="get_rooms_total", required=True)
room_ids = fields.One2many('benefit.housing.rooms', inverse_name='housing_id')
water_bill_account_number = fields.Char(string='water Bill Account Number')
electricity_bill_account_number = fields.Char(string='Electricity Bill Account Number')
water_bill_account_attach = fields.Many2many('ir.attachment',
relation="ir_water_bill_account_number_rel",
column1="water_bill_account_number",
column2="name",
string="water Bill")
electricity_bill_account_attach = fields.Many2many('ir.attachment',
relation="ir_electricity_bill_account_attach_rel",
column1="electricity_bill_account_number",
column2="name",
string="Electricity Bill ")
benefits_total = fields.Integer(string="Benefit Total", compute="get_benefits_total")
benefit_ids = fields.One2many('grant.benefit', 'housing_id', string="Benefits")
family_ids = fields.One2many('benefit.family', 'housing_id', string="Benefits")
total_income = fields.Float(compute='get_total')
total_expenses = fields.Float(compute='get_total')
total_net = fields.Float(compute='get_total')
financial_aid = fields.Float(compute='get_total')
domestic_labor_ids = fields.Many2many('domestic.labor')
def get_html(self):
for rec in self:
print(f'<iframe id="custom_src" height="500" width="500" src="{rec.url}"></iframe>')
rec.url_html = f'<iframe id="custom_src" height="500" width="500" src="{rec.url}"/>'
# @api.multi
def open_map(self):
for Location in self:
url = "http://maps.google.com/maps?oi=map&q="
if Location.street:
url += Location.street.replace(' ', '+')
if Location.city_id:
url += '+' + Location.city_id.name.replace(' ', '+')
url += '+' + Location.city_id.state_id.name.replace(' ', '+')
url += '+' + Location.city_id.country_id.name.replace(' ', '+')
if Location.nearby_mosque:
url += Location.nearby_mosque.replace(' ', '+')
return {
'type': 'ir.actions.act_url',
'target': 'new',
'url': url
}
@api.onchange('url')
def onchange_image_url(self):
if self.image_url:
self.img_attach = '<img id="img" src="%s"/>' % self.url
@api.depends('benefit_ids')
def get_benefits_total(self):
for rec in self:
rec.benefits_total = len(rec.benefit_ids)
def get_total(self):
for rec in self:
for total in rec.benefit_ids:
rec.total_income += total.total_income
rec.total_expenses += total.total_expenses
# rec.total_net = rec.total_expenses - rec.total_income
if rec.total_expenses >= rec.total_income:
rec.total_net = rec.total_expenses - rec.total_income
else:
rec.total_net = rec.total_income - rec.total_expenses
if rec.total_net > 0:
rec.financial_aid = (abs(rec.total_net) * .5)
else:
rec.financial_aid = 0
@api.depends('room_ids')
def get_rooms_total(self):
for rec in self:
if rec.id:
rooms = rec.env['benefit.housing.rooms'].sudo().search([('housing_id', '=', rec.id)])
rec.rooms_number = len(rooms)
@api.onchange('block', 'city_id', 'housing_number', 'house_number')
def _compute_get_name(self):
for rec in self:
if rec.block and rec.city_id and rec.housing_number and rec.house_number:
rec.name = str(rec.housing_number + "-" + rec.house_number + "-" + rec.block + "-" + str(
rec.city_id.code) + "-" + rec.street)
def open_benefits(self):
return {
'name': _("Benefits"),
'view_type': 'form',
'view_mode': 'tree,form',
'views': [(self.env.ref(
'odex_benefit.grant_benefit_tree').id, 'tree'),
(self.env.ref('odex_benefit.grant_benefit_form').id, 'form')],
'res_model': 'grant.benefit',
'type': 'ir.actions.act_window',
'domain': "[('housing_id','=',%s)]" % (self.id),
'target': 'current',
}
def open_rooms(self):
context = {}
context['default_housing_id'] = self.id
return {
'name': _("Rooms"),
'view_type': 'form',
'view_mode': 'tree,form',
'views': [(self.env.ref(
'odex_benefit.housing_rooms_tree').id, 'tree'),
(self.env.ref('odex_benefit.housing_rooms_form').id, 'form')],
'res_model': 'benefit.housing.rooms',
'type': 'ir.actions.act_window',
'context': context,
'domain': "[('housing_id','=',%s)]" % (self.id),
'target': 'current',
}
@api.onchange('room_ids')
def onchange_room_ids(self):
res = {}
items_ids = []
for record in self:
items_ids.append(record.id)
res['domain'] = {'items': [('room_id', 'in', items_ids)]}
return res
class housingRooms(models.Model):
_name = 'benefit.housing.rooms'
_rec_name = 'rooms_type'
_description = "Benefits - housing rooms"
name = fields.Char(related='rooms_type.name')
housing_id = fields.Many2one(
'benefit.housing')
rooms_type = fields.Many2one(
'housing.rooms.type',
string='room',
required=False)
rooms_categories_id = fields.Many2one(
'rooms.categories')
family_members = fields.Integer(
string='',
required=False)
# male_members = fields.Integer(
# string='',
# required=False)
# female_members = fields.Integer(
# string='',
# required=False)
members_ids = fields.One2many(
'housing.rooms.members',
'room_id',
string='')
items = fields.One2many(
comodel_name='benefit.housing.rooms.items',
inverse_name='room_id',
string='items',
required=False)
room_ribs = fields.Char(
compute='_compute_space')
width = fields.Selection(
string='',
selection=[('1', '1'),
('2', '2'),
('3', '3'),
('4', '4'),
('5', '5'),
('6', '6'),
('7', '7'),
('8', '8'),
('9', '9'), ],
required=False, )
length = fields.Selection(
string='',
selection=[('1', '1'),
('2', '2'),
('3', '3'),
('4', '4'),
('5', '5'),
('6', '6'),
('7', '7'),
('8', '8'),
('9', '9'), ],
required=False, )
room_space = fields.Char(
compute='_compute_space')
room_condition = fields.Char(
string='',
required=False)
@api.onchange('width', 'length')
def _compute_space(self):
for i in self:
if i.width and i.length:
i.room_ribs = i.width + "*" + i.length
i.room_space = int(i.width) * int(i.length)
@api.onchange('rooms_type')
def _load_items(self):
items_list = []
for r in self.rooms_type.mapped('items'):
for item in r:
items_list.append(item)
for i in self.items:
if i.item in items_list:
items_list.remove(i.item)
for room in items_list:
self.sudo().update({'items': [(0, 0, {'item': room.id})]})
class HousingRoomsItems(models.Model):
_name = 'benefit.housing.rooms.items'
_description = "Benefits - housing items"
name = fields.Char(
string='',
required=False)
room_id = fields.Many2one(
comodel_name='benefit.housing.rooms')
item = fields.Many2one(
'rooms.items',
string='item',
required=False)
status = fields.Many2one(
'item.status', )
# compute='set_status')
percentage = fields.Float(
string='',
# related="status.percentage",
required=False)
# @api.onchange('percentage')
# def set_status(self):
# for rec in self:
# if rec.percentage:
# print(rec.percentage)
# status = rec.env['item.status'].sudo().search(
# [('minimum_percentage', '<=', rec.percentage)('maximum_percentage', '>=', rec.percentage)])
# rec.status = status.id
class HousingRoomsMembers(models.Model):
_name = 'housing.rooms.members'
_description = "Benefits - housing members"
room_id = fields.Many2one(
'benefit.housing.rooms')
housing_id = fields.Many2one('benefit.housing', related='room_id.housing_id')
rooms_categories_id = fields.Many2one('rooms.categories', related='room_id.rooms_categories_id',
string='',
required=False)
benefit_id = fields.Many2one(
'grant.benefit',
string='')
age = fields.Integer(
string='',
related='benefit_id.age', required=False)
gender = fields.Selection(selection=[('male', 'Male'), ('female', 'Female')], related='benefit_id.gender',
string="Gender")
is_accept = fields.Boolean(
string='',
store=True,
compute='_check_accept',
required=False)
@api.depends('age', 'gender')
def _check_accept(self):
for i in self:
i.is_accept = False
if i.age >= i.room_id.rooms_categories_id.age_from and i.age <= i.room_id.rooms_categories_id.age_to and (
i.gender == i.room_id.rooms_categories_id.gender or i.room_id.rooms_categories_id.gender == 'both'):
i.is_accept = True
class RoomsType(models.Model):
_name = 'housing.rooms.type'
_rec_name = 'name'
_description = "Benefits - rooms type"
name = fields.Char(
string='',
required=False)
items = fields.Many2many('rooms.items',
string='')
class RoomsItems(models.Model):
_name = 'rooms.items'
_rec_name = 'name'
_description = "Benefits - rooms items"
name = fields.Char(
string='',
required=False)
description = fields.Char(
string='Description',
required=False)
class RoomsCategories(models.Model):
_name = 'rooms.categories'
_rec_name = 'name'
_description = "Benefits - rooms categories"
name = fields.Char(
string='',
required=False)
age_from = fields.Integer(
string='',
required=False)
age_to = fields.Integer(
string='',
required=False)
gender = fields.Selection(selection=[('male', 'Male only'), ('female', 'Female only'), ('both', 'both')],
string="Gender")
description = fields.Char(
string='Description',
required=False)
class ItemStatus(models.Model):
_name = 'item.status'
_description = "Benefits - item status"
name = fields.Char(
string='',
required=False)
minimum_percentage = fields.Float(
string='',
required=False)
maximum_percentage = fields.Float(
string='',
required=False)
class DomesticLabor(models.Model):
_name = 'domestic.labor'
_description = "Benefits - domestic labor"
name = fields.Char(string='name')
# @staticmethod
# def _get_default_color():
# return randint(1, 11)
color = fields.Integer(string='Color Index')
class housingNeed(models.Model):
_name = 'housing.need'
_description = 'housing needs'
ap_id = fields.Many2one(
'appliances.furniture')
housing_id = fields.Many2one(
'benefit.housing')
benefit_id = fields.Many2one(
'grant.benefit')
amount = fields.Float(
string='',
required=False)

View File

@ -0,0 +1,22 @@
from odoo import models, fields
class HrDepartment(models.Model):
_inherit = 'hr.department'
operation_manager_id = fields.Many2one('hr.employee', string='Operation Manager')
# def name_get(self):
# result = []
# for department in self:
# name = department.name
# result.append((department.id, name))
# return result
# def name_get(self):
# result = []
# print(self.env.context) # Log the context for debugging
# if self.env.context.get('special_display_name', True):
# for department in self:
# name = department.name
# result.append((department.id, name))
# return result
# return super(HrDepartment, self).name_get()

View File

@ -0,0 +1,77 @@
from odoo import fields, models, api, _
class BenefitAttachment(models.Model):
_inherit = 'ir.attachment'
benefit_id = fields.Many2one('grant.benefit',string="Benefit")
education_status_id = fields.Many2one('education.status')
member_id = fields.Many2one('family.member',string="Member")
expiration_date = fields.Date(string='Expiration date')
attach_status = fields.Selection(selection=[
('valid', 'Valid'),
('expired', 'Expired'),
], string='Attach Status',compute = "get_status",store=True)
allow_days = fields.Integer(compute='get_allow_days',string='Allow Days')
attach_id = fields.Many2one('attachments.settings', string="Attach",domain=[('attach_type', '=', 'member_attach')])
hobbies_id = fields.Many2one('attachments.settings', string="Hobby",domain=[('attach_type', '=', 'hobbies_attach')])
diseases_id = fields.Many2one('attachments.settings', string="Diseases",domain=[('attach_type', '=', 'diseases_attach')])
disabilities_id = fields.Many2one('attachments.settings', string="Disabilities",domain=[('attach_type', '=', 'disabilities_attach')])
hobby_attach = fields.Binary(attachment=True, string="Hobby Attach")
# fields to management required and delete records in benefit attachment
is_required = fields.Boolean(string='Is Required?')
is_default = fields.Boolean(string='Is Default?')
mother_grant_benefit_id = fields.Many2one('grant.benefit', string='Mother Grant Benefit')
replacement_mother_grant_benefit_id = fields.Many2one('grant.benefit', string='Replacement Mother Grant Benefit')
show_in_portal = fields.Boolean(default=False, string="Show In Portal")
def action_preview_attachment(self):
# Custom function to open the preview
return {
'type': 'ir.actions.act_url',
'url': f'/browse/document/{self.id}',
'target': 'new', # Opens in a new tab
}
@api.depends('expiration_date')
def get_status(self):
for rec in self:
today = fields.Date.today()
if rec.expiration_date:
if rec.expiration_date and rec.expiration_date > today:
rec.attach_status = 'valid'
else:
rec.attach_status = 'expired'
else:
rec.attach_status = ''
@api.depends('attach_status')
def get_allow_days(self):
for rec in self:
today = fields.Date.today()
if rec.attach_status == 'expired' and rec.expiration_date:
difference = today - rec.expiration_date
days = difference.days
rec.allow_days = days
else:
rec.allow_days = 0
@api.onchange('hobbies_id')
def onchange_hobbies_id(self):
for rec in self:
if rec.hobbies_id:
rec.name = rec.hobbies_id.name
@api.onchange('diseases_id')
def onchange_diseases_id(self):
for rec in self:
if rec.diseases_id:
rec.name = rec.diseases_id.name
@api.onchange('disabilities_id')
def onchange_disabilities_id(self):
for rec in self:
if rec.disabilities_id:
rec.name = rec.disabilities_id.name

View File

@ -0,0 +1,18 @@
from odoo import models, fields, _
class JobSettings(models.Model):
_name = 'job.settings'
name = fields.Char(required=True)
not_defined = fields.Boolean(default=False)
active = fields.Boolean(default=True)
_sql_constraints = [
(
'uniq_name',
'UNIQUE( name )',
_('This job already exists!')
)
]

View File

@ -0,0 +1,17 @@
from odoo import fields, models
class MainService(models.Model):
_name = 'main.service'
name = fields.Char(string='Name')
service_type = fields.Selection([
('service', 'Service'),
('exception', 'Exception'),
], string='Service Type')
services = fields.Selection([
('experimental_services', 'Experimental Services'),
('exceptional_services', 'Exceptional Services'),
('emergency_services', 'Emergency Services'),
('seasonal_services', 'Seasonal Services'),
('permanent_services', 'Permanent Services'),
], string='Services')

View File

@ -0,0 +1,29 @@
from odoo import fields, models , api
class MemberDisabilities(models.Model):
_name = 'member.disabilities'
name = fields.Char(string="Name")
member_id = fields.Many2one('family.member',string="Member")
disabilities_id = fields.Many2one('disabilities.settings', string="disability")
disability_attach = fields.Binary(attachment=True, string="disability Attach")
expiration_date = fields.Date(string='Expiration date')
attach_status = fields.Selection(selection=[
('valid', 'Valid'),
('expired', 'Expired'),
], string='Attach Status', compute="get_status", store=True)
# fields to management required and delete records in benefit attachment
is_required = fields.Boolean(string='Is Required?')
is_default = fields.Boolean(string='Is Default?')
@api.depends('expiration_date')
def get_status(self):
for rec in self:
today = fields.Date.today()
if rec.expiration_date:
if rec.expiration_date and rec.expiration_date > today:
rec.attach_status = 'valid'
else:
rec.attach_status = 'expired'
else:
rec.attach_status = ''

View File

@ -0,0 +1,29 @@
from odoo import fields, models, api
class MemberDiseases(models.Model):
_name = 'member.diseases'
name = fields.Char(string="Name")
member_id = fields.Many2one('family.member',string="Member")
diseases_id = fields.Many2one('diseases.settings', string="Disease")
disease_attach = fields.Binary(attachment=True, string="Diseases Attach")
expiration_date = fields.Date(string='Expiration date')
attach_status = fields.Selection(selection=[
('valid', 'Valid'),
('expired', 'Expired'),
], string='Attach Status', compute="get_status", store=True)
# fields to management required and delete records in benefit attachment
is_required = fields.Boolean(string='Is Required?')
is_default = fields.Boolean(string='Is Default?')
@api.depends('expiration_date')
def get_status(self):
for rec in self:
today = fields.Date.today()
if rec.expiration_date:
if rec.expiration_date and rec.expiration_date > today:
rec.attach_status = 'valid'
else:
rec.attach_status = 'expired'
else:
rec.attach_status = ''

View File

@ -0,0 +1,6 @@
from odoo import fields, models
class MemberLocation(models.Model):
_name = 'member.location'
name = fields.Char(string="Name")

View File

@ -0,0 +1,31 @@
from odoo import fields, models ,api
class MemberHobbies(models.Model):
_name = 'member.hobbies'
name = fields.Char(string="Name")
member_id = fields.Many2one('family.member',string="Member")
hobbies_id = fields.Many2one('hobbies.settings',string="Hobby")
hobby_attach = fields.Binary(attachment=True,string="Hobby Attach")
expiration_date = fields.Date(string='Expiration date')
attach_status = fields.Selection(selection=[
('valid', 'Valid'),
('expired', 'Expired'),
], string='Attach Status', compute="get_status", store=True)
# fields to management required and delete records in benefit attachment
is_required = fields.Boolean(string='Is Required?')
is_default = fields.Boolean(string='Is Default?')
@api.depends('expiration_date')
def get_status(self):
for rec in self:
today = fields.Date.today()
if rec.expiration_date:
if rec.expiration_date and rec.expiration_date > today:
rec.attach_status = 'valid'
else:
rec.attach_status = 'expired'
else:
rec.attach_status = ''

View File

@ -0,0 +1,252 @@
from odoo import fields, models, api, _
from stdnum.au.acn import to_abn
from odoo.exceptions import ValidationError, UserError
class PaymentOrders(models.Model):
_name = 'payment.orders'
_description = "Payment Orders"
_inherit = ['mail.thread', 'mail.activity.mixin']
_order = 'payment_order_date desc'
def _default_journal(self):
setting = self.env['family.validation.setting'].search([], limit=1)
return setting.payment_journal_id.id if setting and setting.journal_id else False
name = fields.Char(string="Code", copy=False, readonly=True, default=lambda x: _('New'))
# todo handel _compute_ref_num
ref_num = fields.Many2one('seasonal.service', string='Ref. Number', compute='_compute_ref_num')
payment_order_date = fields.Datetime(string="Payment Order Date", default=fields.Datetime.now)
accountant_id = fields.Many2one('res.users', string='Accountant')
# todo remove _compute_service_type_id and _inverse_service_type_id
payment_order_description = fields.Many2one('services.settings',
string='Payment Order Description',
compute='_compute_service_type_id',
inverse='_inverse_service_type_id',
store=True)
service_requests_ids = fields.Many2many(comodel_name='service.request',
relation='service_request_payment_order_rel',
column1='payment_order_id', column2='service_request_id',
string='Service Requests', )
benefit_expense_line_ids = fields.One2many('benefit.expense.line', 'payment_order_id',
string='Benefit Expense Lines')
# todo need to remove seasonal_requests_ids
seasonal_requests_ids = fields.One2many('seasonal.service', 'payment_order_id', string='Seasonal Requests')
state = fields.Selection(string='Status',
selection=[('draft', 'Draft'),
('waiting_head', 'Waiting for Head of Expenses Department'),
('waiting_finance', 'Waiting for Financial Manager'),
('waiting_gm', 'Waiting for General Manager'),
('waiting_deposit', 'Waiting for Deposit'),
('done', 'Done'),
('refused', 'Refused')], default='draft', tracking=True)
is_seasonal = fields.Boolean(string='Is Seasonal Service?')
journal_id = fields.Many2one(comodel_name='account.journal', string="Journal", copy=False,
domain="[('type','in',['cash','bank'])]", 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')
move_count = fields.Integer(string="Move Count", compute='_compute_move_count')
total_amount = fields.Float(string="Total Amount", compute='_compute_total_amount', store=True)
company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.company)
currency_id = fields.Many2one('res.currency', string='Currency',
related='company_id.currency_id')
@api.depends('service_requests_ids', 'benefit_expense_line_ids')
def _compute_total_amount(self):
for rec in self:
if rec.type in ['services', 'seasonal_services']:
rec.total_amount = sum(rec.service_requests_ids.mapped('requested_service_amount'))
elif rec.type == 'benefit_expense':
rec.total_amount = sum(rec.benefit_expense_line_ids.mapped('total_family_expenses'))
else:
rec.total_amount = 0.0
def action_manager_approval(self):
for rec in self:
if self.env.user != rec.accountant_id:
raise ValidationError(_("Only the assigned accountant can approve this payment order."))
rec.state = 'waiting_head'
def action_head_approval(self):
for rec in self:
rec.state = 'waiting_finance'
def action_finance_approval(self):
for rec in self:
rec.state = 'waiting_gm'
def create_entry(self):
for rec in self:
if not rec.journal_id:
raise UserError(_("Please select a journal before creating the entry."))
line_ids = rec.get_lines()
move_vals = {
'journal_id': rec.journal_id.id,
'line_ids': line_ids,
'ref': rec.name + '/' + rec.type,
}
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(move_vals)
# move_id.action_post()
rec.move_id = move_id
def action_deposit(self):
for rec in self:
rec.state = 'done'
def action_gm_approval(self):
for rec in self:
rec.state = 'waiting_deposit'
def action_refuse(self):
for rec in self:
rec.state = 'refused'
def action_reset_to_draft(self):
for rec in self:
rec.state = 'draft'
# Compute method
@api.depends('seasonal_requests_ids')
def _compute_ref_num(self):
for record in self:
record.ref_num = record.seasonal_requests_ids[0] if record.seasonal_requests_ids else False
@api.depends('seasonal_requests_ids.service_type_id')
def _compute_service_type_id(self):
for record in self:
# Take value from first seasonal_requests record (if exists)
record.payment_order_description = record.seasonal_requests_ids[:1].service_type_id
# Inverse method
def _inverse_service_type_id(self):
for record in self:
if record.seasonal_requests_ids:
# Update first related record
record.seasonal_requests_ids[0].service_type_id = record.payment_order_description
else:
# Create new seasonal_requests record if none exists
self.env['seasonal.service'].create({
'payment_order_id': record.id,
'service_type_id': record.payment_order_description.id,
# Add other required fields here if necessary
})
@api.model
def create(self, vals):
res = super(PaymentOrders, self).create(vals)
if not res.name or res.name == _('New'):
res.name = self.env['ir.sequence'].sudo().next_by_code('payment.orders.sequence') or _('New')
return res
def unlink(self):
for payment in self:
if payment.state not in ['draft']:
raise ValidationError(_(
"You cannot delete this payment order.\n"
"Only records in the *Draft* state may be deleted."
))
return super(PaymentOrders, self).unlink()
# todo remove search override
@api.model
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(
"odex_benefit.group_benefit_payment_accountant_accept"):
args += [('accountant_id', '=', self.env.user.id)]
return super(PaymentOrders, self).search(args, offset, limit, order, count)
def _compute_move_count(self):
for rec in self:
rec.move_count = 1 if rec.move_id else 0
def action_open_related_move_records(self):
return {
'name': _('Moves'),
'type': 'ir.actions.act_window',
'res_model': 'account.move',
'view_mode': 'tree,form',
'domain': [('id', 'in', self.move_id.ids)],
}
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 {
'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_family_id.branch.analytic_account_id.id,
'account_id': account_id,
'debit': amount,
'credit': 0.0,
}
def get_lines(self):
lines = []
total_credit = 0
# credit_line_name = _("Total Credit for Family Expenses")
if self.type in ['seasonal_services', 'services']:
if self.service_requests_ids:
for request in self.service_requests_ids:
lines.append(
{
'name': f'{_("Family code")}-{request.family_id.code}-{request.description}-{request.payment_order_id.name}-{request.payment_order_id.ref_num}',
'benefit_family_id': request.family_id.id,
'account_id': request.account_id.id,
'partner_id': request.family_id.partner_id.id,
'analytic_account_id': request.family_id.branch_family_id.branch.analytic_account_id.id,
'debit': request.requested_service_amount,
'credit': 0.0,
}
)
total_credit += request.requested_service_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
payment_type = dict(self._fields['type']._description_selection(self.env)).get(self.type)
lines.append({
'account_id': self.journal_id.default_account_id.id,
'name': f'{self.name}-{payment_type}',
'credit': total_credit,
'debit': 0.0,
})
return [(0, 0, line) for line in lines]

View File

@ -0,0 +1,89 @@
from odoo import fields, models, api
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
benefit_partner_id = fields.Many2one('res.partner')
##### receive zkat alfert ########
receive_zkat_bank_account_id = fields.Many2one('account.account', string="Bank Account For zkat")
receive_zkat_journal_id = fields.Many2one('account.journal', string="Journal For zkat")
receive_zkat_picking_type_id = fields.Many2one('stock.picking.type', 'Picking Type For Receive zkat')
##### zkat alfert ########
zkat_picking_type_id = fields.Many2one('stock.picking.type', 'Picking Type For zkat')
########استلامات الاضاحي###########
receive_Adha_bank_account_id = fields.Many2one('account.account', string="Bank Account For Adha")
receive_Adha_journal_id = fields.Many2one('account.journal', string="Journal For Adha")
receive_Adha_picking_type_id = fields.Many2one('stock.picking.type', "Picking Type For Receive Adha")
##### الاضاحي ########
Adha_picking_type_id = fields.Many2one('stock.picking.type', "Picking Type For Adha")
############## receive.appliances.furniture#######
receive_af_picking_type_id = fields.Many2one('stock.picking.type', "Picking Type For Receive af")
############## appliances.furniture#######
Af_picking_type_id = fields.Many2one('stock.picking.type', "Picking Type For af")
###############R lons#############
receive_loan_bank_account_id = fields.Many2one('account.account', string="Bank Account For Receive loan")
receive_loan_journal_id = fields.Many2one('account.journal', string="Journal For Receive loan")
###############lons#############
loan_bank_account_id = fields.Many2one('account.account', string="Bank Account For loan")
loan_journal_id = fields.Many2one('account.journal', string="Journal For Receive loan")
# @api.multi
def set_values(self):
res = super(ResConfigSettings, self).set_values()
param = self.env['ir.config_parameter'].sudo()
benefit_partner_id = self.benefit_partner_id or False
receive_zkat_bank_account_id = self.receive_zkat_bank_account_id.id or False
receive_zkat_journal_id = self.receive_zkat_journal_id or False
receive_zkat_picking_type_id = self.receive_zkat_picking_type_id or False
zkat_picking_type_id = self.zkat_picking_type_id or False
receive_Adha_bank_account_id = self.receive_Adha_bank_account_id or False
receive_Adha_journal_id = self.receive_Adha_journal_id or False
Adha_picking_type_id = self.Adha_picking_type_id or False
receive_af_picking_type_id = self.Adha_picking_type_id or False
Af_picking_type_id = self.Af_picking_type_id or False
receive_loan_bank_account_id = self.receive_loan_bank_account_id or False
receive_loan_journal_id = self.receive_loan_journal_id or False
loan_bank_account_id = self.loan_bank_account_id or False
loan_journal_id = self.loan_bank_account_id or False
param.set_param('odex_benefit.benefit_partner_id', benefit_partner_id) # 1
param.set_param('odex_benefit.receive_zkat_bank_account_id', receive_zkat_bank_account_id) # 2
param.set_param('odex_benefit.receive_zkat_journal_id', receive_zkat_journal_id) # 3
param.set_param('odex_benefit.receive_zkat_picking_type_id', receive_zkat_picking_type_id) # 4
param.set_param('odex_benefit.zkat_picking_type_id', zkat_picking_type_id) # 5
param.set_param('odex_benefit.receive_Adha_bank_account_id', receive_Adha_bank_account_id) # 6
param.set_param('odex_benefit.receive_Adha_journal_id', receive_Adha_journal_id) # 7
param.set_param('odex_benefit.Adha_picking_type_id', Adha_picking_type_id) # 8
param.set_param('odex_benefit.receive_af_picking_type_id', receive_af_picking_type_id) # 9
param.set_param('odex_benefit.Af_picking_type_id', Af_picking_type_id) # 10
param.set_param('odex_benefit.receive_loan_bank_account_id', receive_loan_bank_account_id) # 11
param.set_param('odex_benefit.receive_loan_journal_id', receive_loan_journal_id) # 12
param.set_param('odex_benefit.loan_bank_account_id', loan_bank_account_id) # 13
param.set_param('odex_benefit.loan_journal_id', loan_journal_id) # 14
return res
@api.model
def get_values(self):
res = super(ResConfigSettings, self).get_values()
params = self.env['ir.config_parameter'].sudo()
res.update(
benefit_partner_id=params.sudo().get_param('odex_benefit.benefit_partner_id', default=""),
receive_zkat_bank_account_id=params.sudo().get_param('odex_benefit.receive_zkat_bank_account_id',
default=""),
receive_zkat_journal_id=params.sudo().get_param('odex_benefit.receive_zkat_journal_id', default=""),
receive_zkat_picking_type_id=params.sudo().get_param('odex_benefit.receive_zkat_picking_type_id',
default=""),
zkat_picking_type_id=params.sudo().get_param('odex_benefit.zkat_picking_type_id', default=""),
receive_Adha_bank_account_id=params.sudo().get_param('odex_benefit.receive_Adha_bank_account_id',
default=""),
receive_Adha_journal_id=params.sudo().get_param('odex_benefit.receive_Adha_journal_id', default=""),
Adha_picking_type_id=params.sudo().get_param('odex_benefit.Adha_picking_type_id', default=""),
receive_af_picking_type_id=params.sudo().get_param('odex_benefit.receive_af_picking_type_id', default=""),
Af_picking_type_id=params.sudo().get_param('odex_benefit.Af_picking_type_id', default=""),
receive_loan_bank_account_id=params.sudo().get_param('odex_benefit.receive_loan_bank_account_id',
default=""),
receive_loan_journal_id=params.sudo().get_param('odex_benefit.receive_loan_journal_id', default=""),
loan_bank_account_id=params.sudo().get_param('odex_benefit.loan_bank_account_id', default=""),
loan_journal_id=params.sudo().get_param('odex_benefit.loan_journal_id', default=""),
)
return res

View File

@ -0,0 +1,7 @@
from odoo import fields, models
class MemberHobbies(models.Model):
_inherit = 'res.country'
is_excluded = fields.Boolean(string='Is Excluded?')

View File

@ -0,0 +1,24 @@
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
import logging
_logger = logging.getLogger(__name__)
class ResPartner(models.Model):
_inherit = "res.partner"
def unlink(self):
env = self.env
for partner in self:
grants = env['grant.benefit'].search([
('partner_id', '=', partner.id),
('state', 'not in', ['draft', 'new'])
])
if grants:
grant_info = ', '.join('[%s: %s]' % (g.code or g.name or g.id, dict(g._fields['state'].selection).get(g.state)) for g in grants)
raise ValidationError(
_("Cannot delete partner '%s': linked to Benefits - Profiles %s") % (partner.name, grant_info)
)
return super().unlink()

View File

@ -0,0 +1,44 @@
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
import logging
_logger = logging.getLogger(__name__)
class ResUsers(models.Model):
_inherit = 'res.users'
def unlink(self):
for user in self:
grants = self.env['grant.benefit'].search([
('user_id', '=', user.id),
('state', 'not in', ['draft', 'new'])
])
if grants:
grant_info = ', '.join('[%s: %s]' % (g.code or g.name or g.id, dict(self.env['grant.benefit']._fields['state'].selection).get(g.state)) for g in grants)
raise ValidationError(
_("Cannot delete user '%s': linked to Benefits - Profiles %s") % (user.name, grant_info)
)
partners = self.mapped('partner_id')
for user in self:
benefits = self.env['grant.benefit'].search([('user_id', '=', user.id)])
benefits.with_context(skip_user_unlink=True).unlink()
res = super(ResUsers, self).unlink()
for partner in partners:
still_linked = self.env['res.users'].search([('partner_id', '=', partner.id)], limit=1)
if not still_linked:
try:
partner.unlink()
except Exception as e:
_logger.warning(
"Failed to delete partner ID %s after user removal. Reason: %s", partner.id, str(e)
)
raise ValidationError(
_("Failed to delete partner '%s' (ID: %s) after user removal. Reason: %s")
% (partner.display_name, partner.id, str(e))
)
return res

View File

@ -0,0 +1,267 @@
from asyncore import write
from odoo import fields, models, api, _
from odoo.exceptions import UserError, ValidationError
from datetime import timedelta
from dateutil.relativedelta import relativedelta
class SeasonalService(models.Model):
_name = 'seasonal.service'
_inherit = ['mail.thread', 'mail.activity.mixin']
_order = "name desc"
name = fields.Char(string='Reference', required=True, copy=False, readonly=True, index=True,
default=lambda self: _('New'))
date = fields.Datetime(string='Request Date', default=fields.Datetime.now, copy=False)
service_type_id = fields.Many2one('services.settings', domain="[('is_seasonal_service','=',True)]",
string="Seasonal Service Type", required=True)
benefit_type = fields.Selection(string='Benefit Type', related='service_type_id.benefit_type')
branch_ids = fields.Many2many('branch.settings', 'service_branch_rel', 'service_id', 'branch_id', string='Branches',
required=True, domain="[('has_employees', '=', True)]")
family_category_ids = fields.Many2many(
'benefit.category',
'service_category_rel',
'service_id',
'category_id',
string='Family Category',
compute='_compute_family_category_ids', )
aid_amount = fields.Float(string="Aid Amount", compute="_compute_amounts", store=True, readonly=False)
benefit_member_count = fields.Integer(string="Benefit Member count", compute="compute_family_benefit", store=True)
family_count = fields.Integer(string="Family count", compute="compute_family_benefit", store=True)
family_disbursement_total_amount = fields.Float(string="Total Family Disbursement Amount",
compute="_compute_family_disbursement", store=True)
payment_order_id = fields.Many2one('payment.orders', string='Payment Order', copy=False, ondelete="set null")
state = fields.Selection(selection=[
('draft', 'Draft'),
('calculated', 'Calculated'),
('gm_assistant', 'Waiting Assistant General Manager'),
('accounting_approve', 'Accounting Approve'),
('waiting_receive', 'Waiting for Receive'),
('done', 'Done'),
], string='state', default='draft', tracking=True, copy=False)
is_payment_order_done = fields.Boolean(string='Is Payment Order Done?', copy=False)
payment_order_state = fields.Selection(string='Payment Order State', selection=[
('none', 'None'),
('waiting', 'Waiting Payment'),
('done', 'Done Payment'), ], copy=False, compute="_compute_payment_order_state", store=True)
account_id = fields.Many2one('account.account', string='Expenses Account', related="service_type_id.account_id")
service_requests_ids = fields.One2many('service.request', 'seasonal_service_id', string='Service Requests')
benefit_ids = fields.Many2many(comodel_name='grant.benefit', relation='benefit_grant_seasonal_service_rel',
column1='seasonal_service_id',
column2='benefit_id', string='Families', copy=False)
member_ids = fields.Many2many(comodel_name='family.member', relation='family_member_seasonal_service_rel',
column1='seasonal_service_id',
column2='family_member_id', string='Family Members', copy=False)
family_domain_ids = fields.Many2many(comodel_name='grant.benefit', compute='_compute_domain_ids',
string="Eligible Families")
service_delivery_method = fields.Selection(selection=[
('cash', 'Cash'),
('in_kind', 'In kind'), ], string='Service Delivery Method', default='cash')
is_in_kind = fields.Boolean(string="In Kind", related="service_type_id.in_kind")
company_id = fields.Many2one('res.company', string="Company", default=lambda self: self.env.user.company_id)
currency_id = fields.Many2one('res.currency', string="Currency", related='company_id.currency_id')
@api.depends('payment_order_id', 'payment_order_id.state')
def _compute_payment_order_state(self):
for rec in self:
payment_order_state = 'none'
if rec.payment_order_state:
if rec.payment_order_id.state == "done":
payment_order_state = "done"
rec.service_requests_ids.write({'state': 'send_request_to_supplier'})
rec.state = 'waiting_receive'
else:
payment_order_state = "waiting"
rec.payment_order_state = payment_order_state
@api.depends('branch_ids', 'family_category_ids')
def _compute_domain_ids(self):
for rec in self:
domain = ['|', ('state', '=', 'second_approve'), '&', ('state', 'in', ('waiting_approve', 'first_approve')),
('action_type', '=', 'suspended')]
if self.branch_ids:
domain.append(('branch_custom_id', 'in', self.branch_ids.ids))
if self.family_category_ids:
domain.append(('benefit_category_id', 'in', self.family_category_ids.ids))
families = self.env['grant.benefit'].sudo().search(domain)
rec.family_domain_ids = families
@api.depends('service_type_id', 'service_type_id.benefit_category_ids')
def _compute_family_category_ids(self):
for record in self:
if record.service_type_id and record.service_type_id.benefit_category_ids:
record.family_category_ids = record.service_type_id.benefit_category_ids
else:
record.family_category_ids = []
@api.model
def create(self, vals):
res = super(SeasonalService, self).create(vals)
if not res.name or res.name == _('New'):
res.name = self.env['ir.sequence'].sudo().next_by_code('seasonal.service.sequence') or _('New')
return res
def unlink(self):
for service in self:
if service.state not in ['draft']:
raise UserError(_('You cannot delete this record'))
return super(SeasonalService, self).unlink()
@api.onchange('service_type_id')
def _onchange_service_type_id(self):
if self.benefit_ids:
self.benefit_ids = [(5, 0, 0)]
if self.member_ids:
self.member_ids = [(5, 0, 0)]
def action_create_payment_order(self):
for rec in self:
if rec.state != 'accounting_approve':
raise UserError(_("All selected requests should be in Accounting Approve state"))
if rec.payment_order_id:
raise UserError(_("There are already disbursement orders associated with the request(s)."))
self.env['payment.orders'].create({
'state': 'draft',
'accountant_id': rec.service_type_id.accountant_id.id,
'seasonal_requests_ids': rec.ids,
'service_requests_ids': rec.service_requests_ids.ids,
'is_seasonal': True,
'type': 'seasonal_services',
})
# rec.payment_order_id = payment_order.id
rec.is_payment_order_done = True
@api.depends('service_requests_ids')
def compute_family_benefit(self):
for record in self:
families = record.service_requests_ids.mapped('family_id')
family_count = len(families)
member_count = sum(record.service_requests_ids.mapped('service_benefit_count'))
record.family_count = family_count
record.benefit_member_count = member_count
@api.depends('service_type_id')
def _compute_amounts(self):
for record in self:
if record.service_type_id and record.service_delivery_method == 'cash':
record.aid_amount = record.service_type_id.max_amount
else:
record.aid_amount = 0
@api.depends('service_requests_ids')
def _compute_family_disbursement(self):
for record in self:
if record.service_requests_ids:
if record.service_delivery_method == "cash":
record.family_disbursement_total_amount = sum(
record.service_requests_ids.mapped('requested_service_amount'))
else:
record.family_disbursement_total_amount = sum(
record.service_requests_ids.mapped('service_qty'))
else:
record.family_disbursement_total_amount = 0.0
def action_first_approval(self):
for rec in self:
if not rec.service_requests_ids:
raise UserError(_("You must add at least one service request."))
if rec.service_type_id.needs_beneficiary_manager_approval:
rec.state = 'gm_assistant'
rec.service_requests_ids.write({'state': 'gm_assistant'})
elif rec.service_delivery_method == "cash":
# rec.action_create_payment_order()
rec.state = "accounting_approve"
rec.service_requests_ids.write({'state': 'accounting_approve'})
elif rec.service_delivery_method == "in_kind":
rec.state = 'waiting_receive'
rec.service_requests_ids.write({'state': 'send_request_to_supplier'})
def action_approval_of_gm_assistant(self):
for rec in self:
if rec.service_delivery_method == "cash":
# rec.action_create_payment_order()
rec.state = "accounting_approve"
rec.service_requests_ids.write({'state': 'accounting_approve'})
elif rec.service_delivery_method == "in_kind":
rec.state = 'waiting_receive'
rec.service_requests_ids.write({'state': 'send_request_to_supplier'})
def action_done(self):
for rec in self:
rec.state = 'done'
rec.service_requests_ids.write({'state': 'family_received_device'})
def action_calculate(self):
for rec in self:
rec._generate_service_requests()
rec.state = 'calculated'
def action_recalculate(self):
for rec in self:
rec.service_requests_ids.unlink()
rec._generate_service_requests()
def _generate_service_requests(self):
Service = self.env['service.request']
for rec in self:
if not rec.benefit_ids:
raise UserError(_("You must add at least one family."))
if rec.benefit_type == "family":
for benefit in rec.benefit_ids:
service_request = Service.create({
'family_id': benefit.id,
'service_cat': rec.service_type_id.id,
'seasonal_service_id': rec.id,
'benefit_type': rec.benefit_type,
})
service_request.onchange_requested_service_amount()
if rec.service_delivery_method == "cash":
service_request.requested_service_amount = service_request.service_max_amount
if service_request.requested_service_amount == 0:
service_request.unlink()
else:
service_request.requested_service_amount = 0
service_request.is_in_kind = True
service_request.service_qty = rec.aid_amount
else:
if not rec.member_ids:
raise UserError(_("You must add at least one member."))
for member in rec.member_ids:
if not member.benefit_id:
raise UserError(_("Member %s has no related family (benefit).") % member.name)
service_request = Service.create({
'family_id': member.benefit_id.id,
'member_id': member.id,
'service_cat': rec.service_type_id.id,
'seasonal_service_id': rec.id,
'benefit_type': rec.benefit_type,
})
service_request.onchange_requested_service_amount()
if rec.service_delivery_method == "cash":
service_request.requested_service_amount = service_request.service_max_amount
if service_request.requested_service_amount == 0:
service_request.unlink()
else:
service_request.requested_service_amount = 0
service_request.is_in_kind = True
service_request.service_qty = rec.aid_amount
def action_reset_to_draft(self):
for rec in self:
rec.service_requests_ids.write({'state': 'draft'})
rec.service_requests_ids.unlink()
rec.state = 'draft'
def action_reset_to_calculated(self):
for rec in self:
rec.service_requests_ids.write({'state': 'draft'})
rec.state = 'calculated'

View File

@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
from odoo import models, fields
class RefuseReason(models.Model):
_name = 'service.refuse.reason'
_description = 'Reasons for Service Rejection'
name = fields.Char(string='Reason', required=True)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,202 @@
from odoo import fields, models, api, _
class ServicesSettings(models.Model):
_name = 'services.settings'
_rec_name = 'service_name'
_order = 'service_number'
service_name = fields.Char(string='Service Name')
benefit_type = fields.Selection(string='Benefit Type', selection=[('family', 'Family'), ('member', 'Member')])
parent_service = fields.Many2one('services.settings',string='Parent Service')
is_main_service = fields.Boolean(string='Is Main Service?')
is_service_producer = fields.Boolean(string='Is Service Producer?')
service_producer_id = fields.Many2one('res.partner',string='Service Producer')
is_this_service_for_student = fields.Boolean(string='Is Service For Student?')
service_type = fields.Selection([('rent', 'Rent'),('home_restoration', 'Home Restoration'),('alternative_housing', 'Alternative Housing'),('home_maintenance','Home Maintenance')
,('complete_building_house','Complete Building House'),('electrical_devices','Electrical Devices'),('home_furnishing','Home furnishing')
,('electricity_bill','Electricity bill'),('water_bill','Water bill'),('buy_car','Buy Car'),('recruiting_driver','Recruiting Driver')
,('transportation_insurance','Transportation Insurance'),('debits','Debits'),('health_care','Health Care'),
('providing_medicines_medical_devices_and_needs_the_disabled','Providing Medicines Medical Devices And Needs The Disabled'),
('recruiting_domestic_worker_or_nurse','Recruiting a domestic worker or nurse') ,('marriage','Marriage'),('eid_gift','Eid gift'),
('winter_clothing','Winter clothing'),('ramadan_basket','Ramadan basket'),('natural_disasters','Natural disasters'),
('legal_arguments','Legal arguments'),('buy_home','Buy Home'),('main_service','Main Service'),('normal_service', 'Normal Service')]
,string='Service Type')
max_amount_for_student = fields.Float(string='Max Amount for Student')
raise_amount_for_orphan = fields.Float(string='Raise Amount For Orphan')
rent_lines = fields.One2many('rent.lines','services_settings_id')
attachment_lines = fields.One2many('service.attachments.settings','service_id')
#Fields for home restoration
category_amount_lines = fields.One2many('category.amount.line','services_settings_id')
rent_amount_for_alternative_housing = fields.Float(string='Rent Amount For Alternative Housing')
rent_period = fields.Integer('Rent Period')
home_maintenance_lines = fields.One2many('home.maintenance.lines','services_settings_id')
benefit_category_ids = fields.Many2many('benefit.category', string='Allowed Categories')
account_id = fields.Many2one('account.account',string='Expenses Account',domain="[('user_type_id.id','=',15)]")
accountant_id = fields.Many2one('res.users',string='Accountant')
#For Electrical Devices
electrical_devices_lines = fields.One2many('electrical.devices','services_settings_id')
#Home Furnishing
home_furnishing_lines = fields.One2many('home.furnishing.lines','services_settings_id')
max_furnishing_amount_if_exception = fields.Float(string='Max Furnishing Amount (Exception)')
bill_lines = fields.One2many('bill.lines', 'services_settings_id')
min_count_member = fields.Integer(string='Mini Count Member')
#Transportation insurance
transportation_insurance_ids = fields.One2many('transportation.insurance', 'services_settings_id')
member_max_payroll = fields.Float(string='Member Max Payroll')
fatherless_member_amount = fields.Float(string='Fatherless Member Amount')
orphan_member_amount = fields.Float(string='Orphan Member Amount')
#Buy Home
limit_person_line_ids = fields.One2many('service.limit.person.line', 'services_settings_id')
buy_home_max_total_amount = fields.Float(string='Buy Home Max Total Amount')
home_age = fields.Integer(string='Home Age')
required_attach = fields.Boolean(string='Required Attach')
is_seasonal_service = fields.Boolean(string='Is Seasonal Service?')
active = fields.Boolean('Active', default=True)
show_in_portal = fields.Boolean(string="Show in Portal",copy=False)
service_number = fields.Char(string="Service Number",copy=False)
service_category = fields.Selection([
('emergency', 'Emergency'),
('permanent', 'Permanent'),
('exceptional', 'Exceptional'),
('seasonal', 'Seasonal'),
], string="Service Category",copy=False)
company_id = fields.Many2one('res.company', string="Company", default=lambda self: self.env.user.company_id)
currency_id = fields.Many2one('res.currency', string="Currency", related='company_id.currency_id')
max_amount = fields.Monetary(string="Maximum Amount", currency_field='currency_id',copy=False)
max_age = fields.Integer(string="Maximum Age",copy=False)
service_description = fields.Text(string="Service Description")
service_conditions = fields.Html(string="Service Conditions")
allowed_recurrence = fields.Selection([
('once', 'Once'),
('periodic', 'Every Period'),
('unlimited', 'Unlimited'),
], string="Allowed Recurrence", default='once')
recurrence_period = fields.Selection([
('months', 'Months'),
('years', 'Years'),],
string="Recurrence Period", default='months'
)
recurrence_interval = fields.Integer(
string="Recurrence Interval",
default=1,
)
requires_visit = fields.Boolean(
string="Requires Visit?"
)
max_limit_type = fields.Selection([
('none', 'No Limit'),
('fixed', 'Fixed Amount'),
('amount_person', 'Amount by Individuals'),
('category', 'Amount by Category'),
('category_person', 'Amount by Category and Individuals'),
('region', 'Amount by Region'),
('service', 'Amount by Service'),
], string="Max Limit Type"
)
needs_beneficiary_manager_approval = fields.Boolean("Needs Beneficiary Manager Approval")
needs_services_head_approval = fields.Boolean(string="Needs Services Head Approval")
needs_legal_approval = fields.Boolean(string="Needs Legal Approval")
needs_project_management_approval = fields.Boolean(string="Needs Project Management Approval")
allow_non_beneficiary = fields.Boolean(string="Allow Non Beneficiary")
max_limit_period = fields.Selection([
('request', 'Per Request'),
('individual', 'Per Individual'),
('month', 'Per Month'),
('year', 'Per Year'),
('recurrence_period', 'For Allowed Recurrence Period'),
], string='Maximum Limit Period')
max_months_limit = fields.Integer(
string='Maximum Number of Months',
help='Specify the maximum allowed number of months when the period type is monthly.'
)
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")
class RentLines(models.Model):
_name = 'rent.lines'
benefit_category_id = fields.Many2one('benefit.category', string='Benefit Category')
services_settings_id = fields.Many2one('services.settings', string='Services Settings')
benefit_count = fields.Integer('Benefit Count')
estimated_rent_branches = fields.Float(string='Estimated Rent Branches')
estimated_rent_governorate = fields.Float(string='Estimated Rent Governorate')
discount_rate_shared_housing = fields.Float(string='Discount Rate For Shared housing')
_sql_constraints = [
(
'uniq_category_count',
'UNIQUE(benefit_category_id, benefit_count)',
_("Couldn't create same benefit category and count")
)
]
class CategoryAmountLine(models.Model):
_name = 'category.amount.line'
benefit_category_id = fields.Many2one('benefit.category', string='Benefit Category')
services_settings_id = fields.Many2one('services.settings', string='Services Settings')
max_amount = fields.Float(string='Max Amount')
class HomeMaintenanceLines(models.Model):
_name = 'home.maintenance.lines'
_rec_name = 'maintenance_name'
services_settings_id = fields.Many2one('services.settings', string='Services Settings')
maintenance_name = fields.Char(string='Maintenance Name')
class ElectricalDevices(models.Model):
_name = 'electrical.devices'
_rec_name = 'device_name'
min_count_member = fields.Integer(string='From')
max_count_member = fields.Integer(string='To')
device_name = fields.Char(string="Device Name")
allowed_quantity = fields.Integer(string='Allowed Quantity')
account_id = fields.Many2one('account.account',string='Expenses Account',domain="[('user_type_id.id','=',15)]")
services_settings_id = fields.Many2one('services.settings')
price_unit = fields.Float()
class HomeFurnishingLines(models.Model):
_name = 'home.furnishing.lines'
services_settings_id = fields.Many2one('services.settings')
name = fields.Char(string="Furnishing Name")
max_furnishing_amount = fields.Float(string='Furnishing Amount')
class BillLines(models.Model):
_name = 'bill.lines'
benefit_category_id = fields.Many2one('benefit.category', string='Benefit Category')
min_count_member = fields.Integer(string='From')
max_count_member = fields.Integer(string='To')
max_amount_for_bill = fields.Float(string='Max Amount For Bill')
services_settings_id = fields.Many2one('services.settings', string='Services Settings')
class ServiceLimitByPersonLine(models.Model):
_name = 'service.limit.person.line'
min_count_member = fields.Integer(string='Minimum Number of Persons')
max_count_member = fields.Integer(string='Maximum Number of Persons')
amount = fields.Float(string='Amount')
services_settings_id = fields.Many2one('services.settings', string='Services Settings')
class TransportationInsurance(models.Model):
_name = 'transportation.insurance'
services_settings_id = fields.Many2one('services.settings')
name = fields.Char(string="Insurance Name", required=True)
limit_amount = fields.Float(required=True)
account_id = fields.Many2one(
'account.account',
string='Expenses Account',
domain="[('user_type_id.id', '=', 15)]",
required=True
)

View File

@ -0,0 +1,23 @@
from odoo import models, fields, _
class SmsConfiguration(models.Model):
_name = 'benefit.sms.configuration'
_inherit = ['mail.thread', 'mail.activity.mixin']
name = fields.Char("name")
case_text = fields.Text("case Text", tracking=True)
state = fields.Selection([
('draft', 'Draft'),
('complete_info', 'Complete Information'),
('waiting_approve', 'Waiting Approved'),
('approve', 'Approved'),
('add_family', 'add Family'),
('first_refusal', 'First Refusal'),
('refused', 'Refused'),
('black_list', 'Black List'),
('approve_family', 'Approve Family'),
('zkat', 'zkat'),
('adha', 'adha'),
('loans', 'loans'),
])

View File

@ -0,0 +1,403 @@
from odoo import fields, models, api, _
import math, random
from odoo.exceptions import UserError, ValidationError
from datetime import timedelta
import werkzeug
class Visit(models.Model):
_name = 'visit.location'
_inherit = ['mail.thread', 'mail.activity.mixin']
_order = 'create_date desc'
@api.model
def _default_researcher_team(self):
researcher_team = self.env['committees.line'].search([('employee_id', 'in', [self.env.user.employee_id.id])],
limit=1)
return researcher_team.id
benefit_type = fields.Selection([
('benefit', 'Benefit'),
('family', 'Family'),
], string='Type', default="benefit")
benefit_id = fields.Many2one(
'grant.benefit', string='Family file', domain="[('state', '=', 'second_approve')]")
benefit_name = fields.Char(related="benefit_id.name")
benefit_code = fields.Char(related="benefit_id.code")
sms_phone = fields.Char(string="Contact Phone", related="benefit_id.sms_phone")
researcher_team = fields.Many2one("committees.line", string="Researcher Team", related="benefit_id.researcher_id")
researcher_ids = fields.Many2many("hr.employee", string="Researcher", compute="get_researcher_ids", readonly=False)
visit_date = fields.Datetime(string='Visit Date', tracking=True)
description = fields.Char(string='Description')
message = fields.Text(string='Message')
visit_objective = fields.Selection([
('inform_visit', 'Inform Visit'),
('objective_visit', 'Objective Visit'),
], string='Visit Objective')
visit_types = fields.Many2one(
'visits.types',
string='Visits Types',
ondelete='restrict'
)
visit_types_creation_method = fields.Selection(related='visit_types.creation_method')
evaluation = fields.Selection(
[('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6')],
string='Evaluation')
state = fields.Selection([
('draft', 'Draft'),
('contact', 'Contact'),
('schedule_a_visit', 'Schedule a visit'),
('pending', 'Pending'),
('done', 'Done'),
('close', 'Close'),
('cancel', 'Cancel'),
], string='State', default="draft", tracking=True, group_expand='_expand_states')
color = fields.Integer('Color Index', default=0)
family_id = fields.Many2one('benefit.family')
reason = fields.Text(string='Reason/Justification')
name = fields.Char(string='Reference', required=True, copy=False, readonly=True, index=True,
default=lambda self: _('New'))
otp_code = fields.Char(string="OTP Code", readonly=True, copy=False)
otp_generated_at = fields.Datetime(string="OTP Generated At", readonly=True, copy=False)
response_id = fields.Many2one('survey.user_input', string="Survey Responses", copy=False)
response_count = fields.Integer(compute="_compute_response_count", store=True, string="Responses Count", copy=False)
survey_url = fields.Char(string="Survey URL")
def action_postpone(self):
"""Open wizard to postpone"""
context = dict(self.env.context or {})
context['target_state'] = "pending"
context['active_id'] = self.id
return {
'name': _('Postpone Visit'),
'view_mode': 'form',
'view_type': 'form',
'type': 'ir.actions.act_window',
'res_model': 'visit.location.refusal.reason.wizard',
'view_id': self.env.ref('odex_benefit.view_visit_location_refusal_reason_wizard_form').id,
'target': 'new',
'context': context,
}
def action_reschedule(self):
for rec in self:
rec.state = "contact"
def action_create_new_visit(self):
for rec in self:
new_visit = self.create({
'creation_type': rec.creation_type,
'visit_types': rec.visit_types.id,
'benefit_id': rec.benefit_id.id,
'researcher_ids': [(6, 0, rec.researcher_ids.ids)],
'visit_date': fields.Datetime.now(),
'state': 'draft',
})
return {
'type': 'ir.actions.act_window',
'res_model': 'visit.location',
'view_mode': 'form',
'res_id': new_visit.id,
}
@api.depends('response_id')
def _compute_response_count(self):
for rec in self:
rec.response_count = self.env['survey.user_input'].search_count([('visit_id', '=', rec.id)])
def action_view_responses(self):
self.ensure_one()
return {
'name': _("Family Evaluation Responses"),
'type': 'ir.actions.act_window',
'res_model': 'survey.user_input',
'view_mode': 'tree,form',
'domain': [('visit_id', '=', self.id)],
'context': {'create': False},
}
def _expand_states(self, states, domain, order):
return [key for key, val in type(self).state.selection]
def unlink(self):
for order in self:
if order.state not in ['draft'] or order.visit_types.creation_method == 'automatic':
raise UserError(_('You cannot delete this record'))
return super(Visit, self).unlink()
@api.model
def create(self, vals):
# If the 'name' field is 'New', generate a new sequence number
if vals.get('name', _('New')) == _('New'):
vals['name'] = self.env['ir.sequence'].next_by_code('visit.location.sequence') or _('New')
return super(Visit, self).create(vals)
def assign_sequence_to_records(self):
sequence = self.env['ir.sequence']
sorted_records = self.sorted(lambda r: r.create_date)
for record in sorted_records:
if not record.name or record.name == _('New'):
record.name = sequence.next_by_code('visit.location.sequence')
def get_researchers_email(self):
email_ids = ''
for rec in self.researcher_ids:
if email_ids:
email_ids = email_ids + ',' + str(rec.work_email)
else:
email_ids = str(rec.work_email)
return email_ids
def action_draft(self):
self.state = 'draft'
def action_contact(self):
self.state = 'contact'
if self.benefit_id.contact_type == 'email':
template = self.env.ref('odex_benefit.schedule_a_visit_email_template', False)
if not template:
return
template.with_context(lang=self.env.user.lang).send_mail(self.id, force_send=True,
raise_exception=False)
elif self.benefit_id.contact_type == 'sms':
self.benefit_id.partner_id.send_sms_notification(self.message, self.benefit_id.sms_phone)
def action_schedule_a_visit(self):
self.state = 'schedule_a_visit'
def action_cancel(self):
context = dict(self.env.context or {})
context['target_state'] = "cancel"
context['active_id'] = self.id
return {
'name': _('Refuse Reason Wizard'),
'view_mode': 'form',
'view_type': 'form',
'type': 'ir.actions.act_window',
'res_model': 'visit.location.refusal.reason.wizard',
'view_id': self.env.ref('odex_benefit.view_visit_location_refusal_reason_wizard_form').id,
'target': 'new',
'context': context,
}
def action_done(self):
if self.visit_types.otp_verification:
otp_validity = self.visit_types.otp_validity_minutes or 5
expired = (
not self.otp_code
or not self.otp_generated_at
or fields.Datetime.now() > self.otp_generated_at + timedelta(minutes=otp_validity)
)
if expired:
self.otp_code = self.generateOTP()
self.otp_generated_at = fields.Datetime.now()
if self.benefit_id.contact_type == 'email':
if not self.benefit_id.email:
raise UserError(
_("The family profile has no email address. OTP cannot be sent. Please add an email first."))
template = self.env.ref('odex_benefit.visit_location_otp_email_template', False)
if not template:
raise UserError(
_("The email template 'Visit Location OTP Email' is missing. Please contact your administrator."))
template.write({'email_to': self.benefit_id.email,
'email_cc': self.env.user.company_id.hr_email or self.env.user.company_id.email, })
email_values = {"email_from": self.env.user.company_id.hr_email or self.env.user.company_id.email,
'res_id': None}
template.with_context({'lang': self.env.user.lang}).send_mail(self.id, force_send=True,
raise_exception=False, email_values=email_values)
elif self.benefit_id.contact_type == 'sms':
if not self.benefit_id.sms_phone:
raise UserError(
_("The family profile has no mobile number. Please add a valid phone number before sending OTP."))
sms_template_id = self.env.ref('odex_benefit.visit_location_otp_sms_template')
if not sms_template_id:
raise UserError(
_("The SMS template 'Visit Location OTP' is missing. Please contact your administrator."))
sms_body = sms_template_id._render_template(sms_template_id.body,self._name,[self.id],post_process=True)[self.id]
sms_values = {
'number': self.benefit_id.sms_phone,
'body': sms_body,
'partner_id': self.benefit_id.partner_id.id,
'state': 'outgoing',
}
self.env['sms.sms'].sudo().create(sms_values).send()
# don't delete this code
# bot = self.env.ref('base.partner_root').id
# self.with_context(tracking_disable=True)._message_sms_with_template(
# template=sms_template_id,
# put_in_queue=False,
# partner_ids=self.benefit_id.partner_id.ids,
# author_id=bot
# )
# message = _("Your verification code is %s. It is valid for %s minutes.") % (
# self.otp_code,
# self.visit_types.otp_validity_minutes or 5
# )
# self.benefit_id.user_id.send_sms_to_user(message, self.benefit_id.sms_phone)
context = dict(self.env.context or {})
context['active_id'] = self.id
return {
'name': _('Verify OTP'),
'view_mode': 'form',
'view_type': 'form',
'type': 'ir.actions.act_window',
'res_model': 'visit.location.otp.wizard',
'view_id': self.env.ref('odex_benefit.visit_location_otp_wizard_form').id,
'target': 'new',
'context': context,
}
else:
self.state = 'done'
self.benefit_id.last_visit_date = self.visit_date
self.action_send_survey()
def action_skip_otp(self):
self.ensure_one()
context = dict(self.env.context or {})
context['active_id'] = self.id
return {
'name': _('Skip OTP Verification'),
'type': 'ir.actions.act_window',
'res_model': 'visit.skip.otp.wizard',
'view_mode': 'form',
'view_type': 'form',
'view_id': self.env.ref('odex_benefit.view_visit_skip_otp_wizard_form').id,
'target': 'new',
'context': context,
}
def action_send_survey(self):
self.ensure_one()
if self.visit_types.survey_id:
survey = self.visit_types.survey_id
if self.response_id:
response = self.response_id
if response.survey_id.id != survey.id or response.state != 'done':
response.sudo().unlink()
self.response_id = False
if not self.response_id:
response = survey.sudo()._create_answer(
user=self.benefit_id.user_id,
partner=self.benefit_id.partner_id,
email=self.benefit_id.email,
test_entry=False,
check_attempts=True,
visit_id=self.id
)
self.response_id = response.id
else:
response = self.response_id
self.survey_url = '%s%s?%s' % (
survey.get_base_url(),
survey.get_start_url(),
# werkzeug.urls.url_encode({'answer_token': response.access_token})
werkzeug.urls.url_encode({'answer_token': response and response.access_token or None})
)
link_tracker = self.env['link.tracker'].sudo().create({
'url': self.survey_url,
'title': 'Survey Link',
'campaign_id': False,
'medium_id': False,
'source_id': False,
})
self.survey_url = link_tracker.short_url
if self.benefit_id.contact_type == 'email':
if not self.benefit_id.email:
raise UserError(_("The family profile has no email address. Please add an email first."))
template = self.env.ref('odex_benefit.visit_location_survey_email_template', False)
if not template:
raise UserError(_("The email template 'Visit Location Survey Email' is missing."))
email_values = {"email_from": self.env.user.company_id.hr_email or self.env.user.company_id.email,"res_id": None}
template.write({'email_to': self.benefit_id.email,
'email_cc': self.env.user.company_id.hr_email or self.env.user.company_id.email, })
template.with_context(
lang=self.env.user.lang,
survey_url=self.survey_url
).send_mail(self.id, force_send=True, raise_exception=False, email_values=email_values)
elif self.benefit_id.contact_type == 'sms':
if not self.benefit_id.sms_phone:
raise UserError(_("The family profile has no mobile number. Please add a valid phone number."))
sms_template = self.env.ref('odex_benefit.visit_location_survey_sms_template', False)
if not sms_template:
raise UserError(_("The SMS template 'Visit Location Survey' is missing."))
sms_body = sms_template._render_template(sms_template.body, self._name, [self.id], post_process=True)[self.id]
sms_values = {
'number': self.benefit_id.sms_phone,
'body': sms_body,
'partner_id': self.benefit_id.partner_id.id,
'state': 'outgoing',
}
self.env['sms.sms'].sudo().create(sms_values).send()
# self.with_context(tracking_disable=True, survey_url=self.survey_url)._message_sms_with_template(
# template=sms_template,
# put_in_queue=False,
# partner_ids=self.benefit_id.partner_id.ids,
# author_id=self.env.ref('base.partner_root').id
# )
# def action_close(self):
# self.ensure_one()
# if self.visit_types.survey_id:
# if not self.response_id:
# raise UserError(_("You must send the evaluation form before closing the visit."))
# if self.response_id.state != 'done':
# raise UserError(_("The visit cannot be closed before the family completes the evaluation form."))
# self.state = 'close'
@api.depends("researcher_team")
def get_researcher_ids(self):
for rec in self:
rec.researcher_ids = rec.researcher_team.employee_id
def send_visit_date_email(self):
template = self.env.ref('odex_benefit.visit_date_email', False)
if not template:
return
template.with_context(lang=self.env.user.lang).send_mail(self.id, force_send=True, raise_exception=False)
# function to generate OTP
def generateOTP(self):
digits = "0123456789"
OTP = ""
# length of password can be changed
# by changing value in range
for i in range(4):
OTP += digits[math.floor(random.random() * 10)]
return OTP
def geo_localize(self):
for visit in self:
if visit.benefit_id:
url = "http://maps.google.com/maps/search/?api=1&query=%s,%s" % (
visit.benefit_id.lat, visit.benefit_id.lon),
return {
'type': 'ir.actions.act_url',
'target': 'new',
'url': url
}
def get_url_local(self):
for visit in self:
if visit.benefit_id:
url = "http://maps.google.com/maps/search/?api=1&query=%s,%s" % (
visit.benefit_id.lat, visit.benefit_id.lon)
return url
class MemberEducationStatus(models.Model):
_name = 'member.education.status'
name = fields.Char()

View File

@ -0,0 +1,13 @@
from odoo import api, fields, models, exceptions, _
class SurveyUserInput(models.Model):
_inherit = 'survey.user_input'
visit_id = fields.Many2one('visit.location', string="Visit")
def _mark_done(self):
super(SurveyUserInput, self)._mark_done()
self.sudo().visit_id.write({
'state': 'close'
})

View File

@ -0,0 +1,11 @@
from odoo import models, fields
class WeakCourse(models.Model):
_name = 'weak.course'
education_status_id = fields.Many2one('education.status')
weak_course_id = fields.Many2one('study.material', required=True)
result_before = fields.Char('Result before remedial class')
remedial_class_name = fields.Char()
result_after = fields.Char('Result after remedial class')

View File

@ -0,0 +1,2 @@
from . import benefit_report
from . import family_bank_report

View File

@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
import io
import base64
import matplotlib.pyplot as plt
from odoo import api, fields, models, tools, _
from odoo.exceptions import ValidationError, UserError
from datetime import datetime, timedelta, date
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
import arabic_reshaper
from bidi.algorithm import get_display
import io
import base64
import matplotlib.pyplot as plt
class BenefitREP(models.AbstractModel):
_name = 'report.odex_benefit.template_generate_benefit_report_pdf'
@api.model
def _get_report_values(self, docids, data=None):
benefits = data['benefits']
needs = data['needs']
family = data['family']
rooms = data['rooms']
length = data['length']
header = data['header']
ar_headers = data['ar_headers']
f_data = []
benefits = self.env['grant.benefit'].sudo().search([('id', 'in', benefits)])
benefits_need_ids = self.env['benefits.needs'].sudo().search([('id', 'in', needs)])
family_need_ids = self.env['benefit.family'].sudo().search([('id', 'in', family)])
housing_room_ids = self.env['housing.rooms.members'].sudo().search([('id', 'in', rooms)])
result = benefits if benefits else benefits_need_ids if benefits_need_ids else family_need_ids if family_need_ids else housing_room_ids
for i in result:
test = []
for x in header:
z = i[x]
if type(z).__name__ not in ['str', 'int', 'date', 'bool', 'float']:
z = z.name
if type(z).__name__ == 'float':
z = round(z, 2)
if z == True: # TODO
z = 'نعم'
if z == 'false': # TODO
z = 'لا'
if z == 'male': # TODO
z = 'ذكر'
if z == 'female': # TODO
z = 'أنثى'
test.append(z)
f_data.append(test)
age_from, age_to = ' / ', ' / '
if data['age_from'] and data['age_to']:
age_from = data['age_from']
age_to = data['age_to']
name = data['name']
return {
'name': name,
'date_from': age_from,
'age_to': age_to,
'docs': header,
'record': data,
'data': f_data,
'data_len': len(f_data),
'header': header,
'ar_headers': ar_headers,
'benefits': benefits,
'length': length,
}

View File

@ -0,0 +1,118 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<report
id="generate_benefit_report_pdf"
model="generate.reports"
string="Benefit Report"
report_type="qweb-pdf"
name="odex_benefit.template_generate_benefit_report_pdf"
file="odex_benefit.template_generate_benefit_report_pdf"
menu="False"/>
<template id="template_generate_benefit_report_pdf">
<t t-call="web.html_container">
<t t-call="web.external_layout">
<div class="page">
<center>
<h3>
<span t-esc="record['name']"/>
</h3>
</center>
<table class="table table-condensed table-bordered"
style="table-layout: fixed">
<t t-foreach="length" t-as="lenth">
<th style="background-color: #b8bcbf;width:100%;">
<span t-esc="record['ar_headers'][lenth]"/>
</th>
</t>
<t t-foreach="data_len" t-as="ln">
<!-- <t t-foreach="data_len" t-as="rec">-->
<tr>
<t t-foreach="data[ln]" t-as="rec">
<td>
<span t-esc="rec"/>
</td>
</t>
</tr>
</t>
</table>
</div>
</t>
</t>
</template>
<!--service_to == 'benefit'-->
<!-- <template id="benefit_report_pdf">-->
<!-- <t t-call="web.html_container">-->
<!-- <t t-call="web.external_layout">-->
<!-- <div class="page">-->
<!-- &lt;!&ndash; <t t-foreach="docs" t-as="doc">&ndash;&gt;-->
<!-- <h2 colspan="10" class="text-center" style="color:#f7f7f7;font-size:20px">-->
<!-- <span t-esc="name"/>-->
<!-- <span t-esc="family_id"/>-->
<!-- <span t-esc="benefit_id"/>-->
<!-- <span t-esc="housing_id"/>-->
<!-- <span t-esc="age_from"/>-->
<!-- - -->
<!-- <span t-esc="age_to"/>-->
<!-- </h2>-->
<!-- <table class="table table-condensed table-bordered">-->
<!-- <thead class="text-center">-->
<!-- <tr style="background-color: #b8bcbf;width:100%;">-->
<!-- <th style="text-align:center;">#</th>-->
<!-- <th style="text-align:center;">name</th>-->
<!-- <th style="text-align:center;">gender</th>-->
<!-- <th style="text-align:center;">age</th>-->
<!-- <th style="text-align:center;">family</th>-->
<!-- <th style="text-align:center;">behavior</th>-->
<!-- <th style="text-align:center;">need_type_ids</th>-->
<!-- <th style="text-align:center;">fat</th>-->
<!-- <th style="text-align:center;">education_status</th>-->
<!-- <th style="text-align:center;">memorization</th>-->
<!-- <th style="text-align:center;">specialty</th>-->
<!-- <th style="text-align:center;">omra date</th>-->
<!-- </tr>-->
<!-- </thead>-->
<!-- <tbody class="text-center">-->
<!-- <t t-set="sequence" t-value="0"/>-->
<!-- <t t-foreach="docs" t-as="doc">-->
<!-- <tr>-->
<!-- <td>-->
<!-- <t t-set="sequence" t-value="sequence +1"/>-->
<!-- <t t-esc="sequence"/>-->
<!-- </td>-->
<!-- <td class="text-center">-->
<!-- <span t-esc="doc.name"/>-->
<!-- </td>-->
<!-- <td class="text-center">-->
<!-- <span t-esc="doc.gender"/>-->
<!-- </td>-->
<!-- <td class="text-center">-->
<!-- <span t-esc="doc.age"/>-->
<!-- </td>-->
<!-- </tr>-->
<!-- </t>-->
<!-- </tbody>-->
<!-- </table>-->
<!-- &lt;!&ndash; </t>&ndash;&gt;-->
<!-- <div style="page-break-before: always;"></div>-->
<!-- </div>-->
<!-- </t>-->
<!-- </t>-->
<!-- </template>-->
<!-- <report-->
<!-- id="benefit_report_pdf_act"-->
<!-- model="grant.benefit"-->
<!-- string="Benefit Report"-->
<!-- report_type="qweb-pdf"-->
<!-- name="odex_benefit.benefit_report_pdf"-->
<!-- file="odex_benefit.benefit_report_pdf"-->
<!-- menu="False"/>-->
</data>
</odoo>

View File

@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models, tools, _
from odoo.exceptions import ValidationError, UserError
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
class FamilyBankReportXlsx(models.AbstractModel):
_name = 'report.odex_benefit.family_bank_report_xlsx'
_description = 'Family Bank Report XLSX'
_inherit = 'report.report_xlsx.abstract'
@api.model
def generate_xlsx_report(self, workbook, data, objs):
sheet = workbook.add_worksheet(_('Family Bank Report'))
header_format = workbook.add_format({
'bold': True,
'align': 'center',
'valign': 'vcenter',
'bg_color': '#4472C4',
'font_color': 'white',
'border': 1,
'text_wrap': True
})
subheader_format = workbook.add_format({
'bold': True,
'align': 'center',
'valign': 'vcenter',
'bg_color': '#D3D3D3',
'border': 1,
'font_size': 9
})
normal = workbook.add_format({
'align': 'center',
'valign': 'vcenter',
'border': 1
})
bold = workbook.add_format({
'bold': True,
'align': 'center',
'valign': 'vcenter',
'border': 1
})
sheet.set_row(0, 30)
sheet.set_row(1, 25)
sheet.set_row(2, 25)
sheet.merge_range('A1:A2', 'Bank Name' + '\nاسم البنك', header_format)
sheet.merge_range('B1:B2', 'Account Number(24N)' + '\nرقم الحساب', header_format)
sheet.merge_range('C1:C2', 'Beneficiary Name' + '\nاسم المستفيد', header_format)
sheet.merge_range('D1:D2', 'Amount(15)' + '\nقيمة الحوالة', header_format)
sheet.merge_range('E1:E2', 'Civilian_Id(20)' + '\nرقم الهوية', header_format)
sheet.merge_range('F1:F2', 'Currency (3N)' + '\nالعملة', header_format)
sheet.merge_range('G1:G2', 'Beneficiaries Remarks (30)' + '\nملاحظات المستفيد', header_format)
sheet.merge_range('H1:H2', 'Payment Purpose' + '\nغرض الدفع', header_format)
sheet.merge_range('I1:I2', 'Beneficiary Email' + '\nالبريد الإلكتروني للمستفيد', header_format)
row = 3
total_amount = 0
for line in data['lines']:
sheet.write(row, 0, line['bank_name'], normal)
sheet.write(row, 1, line['account_number'], normal)
sheet.write(row, 2, line['beneficiary_name'], normal)
sheet.write_number(row, 3, line['transfer_amount'], normal)
sheet.write(row, 4, line['beneficiary_id'], normal)
sheet.write(row, 5, line['currency'], normal)
sheet.write(row, 6, line['family_code'], normal)
sheet.write(row, 7, line['purpose'], normal)
sheet.write(row, 8, line.get('beneficiary_email', ''), normal)
total_amount += line['transfer_amount']
row += 1
sheet.set_column('A:A', 25)
sheet.set_column('B:B', 25)
sheet.set_column('C:C', 30)
sheet.set_column('D:D', 15)
sheet.set_column('E:E', 20)
sheet.set_column('F:F', 12)
sheet.set_column('G:G', 25)
sheet.set_column('H:H', 20)
sheet.set_column('I:I', 30)

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<record id="action_family_bank_report_xlsx" model="ir.actions.report">
<field name="model">family.bank.report.wizard</field>
<field name="name">Family Bank Report (Excel)</field>
<field name="report_type">xlsx</field>
<field name="report_name">odex_benefit.family_bank_report_xlsx</field>
<field name="report_file">odex_benefit.family_bank_report_xlsx</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,171 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_benefit_researcher_record,access_benefit_researcher_record,model_grant_benefit,odex_benefit.group_benefit_researcher,1,1,1,0
access_benefit_woman_commitee_record,access_benefit_record,model_grant_benefit,odex_benefit.group_benefit_woman_commitee,1,1,1,1
access_benefit_branch_manager_record,access_benefit_branch_manager_record,model_grant_benefit,odex_benefit.group_benefit_branch_manager,1,1,1,1
access_benefit_manager_record,access_benefit_manager_record,model_grant_benefit,odex_benefit.group_benefit_manager,1,1,1,1
access_benefit_edit_record,access_benefit_edit_record,model_grant_benefit,odex_benefit.group_benefit_edit,1,1,1,1
access_education_status_all,education_status,model_education_status,odex_benefit.group_benefit_info,1,1,1,1
access_education_status_all_users,education_status_all_users,model_education_status,,1,0,0,0
access_weak_course_all,weak_course,model_weak_course,odex_benefit.group_benefit_info,1,1,1,1
access_benefit_family_record,access_benefit_family_record,model_benefit_family,,1,1,1,0
access_benefit_record_city,access_benefit_record_city,model_res_country_city,,1,1,0,0
access_benefit_record_reason,access_benefit_record_reason,model_entity_refuse_reason,,1,1,1,0
access_benefit_domestic_labor,access_domestic_labor,model_domestic_labor,,1,1,1,1
access_benefit_widow_family,access_widow_family,model_widow_family,,1,1,1,1
access_benefit_divorcee_family,access_divorcee_family,model_divorcee_family,,1,1,1,1
access_external_request,access_external_request,model_external_request,,1,1,1,1
access_benefit_food_basket,access_benefit_food_basket,model_benefit_food_basket,,1,1,1,1
access_food_basket_line,access_food_basket_line,model_food_basket_line,,1,1,1,1
access_benefit_zkat,access_benefit_zkat,model_benefit_zkat,,1,1,1,1
access_payment_collection_line,access_payment_collection_line,model_payment_collection_line,,1,1,1,1
access_benefit_food_surplus,access_benefit_food_surplus,model_benefit_food_surplus,,1,1,1,1
access_food_surplus_line,access_food_surplus_line,model_food_surplus_line,,1,1,1,1
access_food_surplus_type,access_food_surplus_type,model_food_surplus_type,,1,1,1,1
access_benefit_loans,access_benefit_loans,model_benefit_loans,,1,1,1,1
access_appliances_furniture,access_appliances_furniture,model_appliances_furniture,,1,1,1,1
access_specialization_specialization,access_specialization_specialization,model_specialization_specialization,,1,1,1,1
access_sport_type,access_sport_type,model_sport_type,,1,1,1,1
access_insurance_company,access_insurance_company,model_insurance_company,,1,1,1,1
access_other_associations,access_other_associations,model_other_associations,,1,1,1,1
access_craft_skills,access_craft_skills,model_craft_skills,,1,1,1,1
access_training_inclinations,access_training_inclinations,model_training_inclinations,,1,1,1,1
access_appliances_furniture_need,access_appliances_furniture_need,model_appliances_furniture_need,,1,1,1,1
access_salary_line,access_salary_line,model_salary_line,,1,1,1,1
access_benefit_club,access_benefit_club,model_benefit_club,,1,1,1,1
access_benefit_programs,access_benefit_programs,model_benefit_programs,,1,1,1,1
access_benefit_housing,access_benefit_housing,model_benefit_housing,,1,1,0,0
access_benefit_housing,access_benefit_housing,model_benefit_housing,,1,1,1,1
access_benefit_housing_rooms,access_benefit_housing_rooms,model_benefit_housing_rooms,,1,1,1,1
access_benefit_housing_rooms_items,access_benefit_housing_rooms_items,model_benefit_housing_rooms_items,,1,1,1,1
access_housing_rooms_type,access_housing_rooms_type,model_housing_rooms_type,,1,1,1,1
access_rooms_items,access_rooms_items,model_rooms_items,,1,1,1,1
access_item_status,access_item_status,model_item_status,,1,1,1,1
access_rooms_categories,access_rooms_categories,model_rooms_categories,,1,1,1,1
access_housing_rooms_members,access_housing_rooms_members,model_housing_rooms_members,,1,1,1,1
access_item_status,access_item_status,model_item_status,,1,1,1,1
access_generate_reports,access_generate_reports,model_generate_reports,,1,1,1,1
access_food_basket_benefits_line,access_food_basket_benefits_line,model_food_basket_benefits_line,,1,1,1,1
access_benefit_family_record_officer,access_benefit_family_record_officer,model_benefit_family,,1,1,1,1
access_benefit_record_city_officer,access_benefit_record_city_officer,model_res_country_city,,1,1,1,1
access_external_benefits,access_external_benefits,model_external_benefits,,1,1,1,0
access_benefits_representative,access_benefits_representative,model_benefits_representative,,1,1,1,0
access_benefits_needs,access_benefits_needs,model_benefits_needs,,1,1,1,0
access_needs_payment_line,access_needs_payment_line,model_needs_payment_line,,1,1,1,0
access_needs_categories,access_needs_categories,model_needs_categories,,1,1,1,0
access_benefit_need,access_benefit_need,model_benefit_need,,1,1,1,0
access_house_need,access_house_need,model_house_need,,1,1,1,0
access_generate_reports_log,access_generate_reports_log,model_generate_reports_log,,1,1,1,0
access_program_plane_line,access_program_plane_line,model_program_plane_line,,1,1,1,0
access_benefit_club_activity,access_benefit_club_activity,model_benefit_club_activity,,1,1,1,0
access_receive_benefit_loans,access_receive_benefit_loans,model_receive_benefit_loans,,1,1,1,0
access_purchase_product_loan,access_purchase_product_loan,model_purchase_product_loan,,1,1,1,0
access_receive_food_surplus,access_receive_food_surplus,model_receive_food_surplus,,1,1,1,0
access_receive_appliances_furniture,access_receive_appliances_furniture,model_receive_appliances_furniture,,1,1,1,0
access_donations_type,access_donations_type,model_donations_type,,1,1,1,0
access_receive_benefit_zkat,access_receive_benefit_zkat,model_receive_benefit_zkat,,1,1,1,0
access_zkat_line,access_zkat_line,model_zkat_line,,1,1,1,0
access_benefit_zkat_line,access_benefit_zkat_line,model_benefit_zkat_line,,1,1,1,0
access_receive_food_basket,access_receive_food_basket,model_receive_food_basket,,1,1,1,0
access_benefit_sms_configuration,access_benefit_sms_configuration,model_benefit_sms_configuration,,1,1,1,0
access_benefit_category,access_benefit_category,model_benefit_category,,1,1,1,1
access_sport_line,access_sport_line,model_sport_line,,1,1,1,0
access_benefit_behaviors,access_benefit_behaviors,model_benefit_behaviors,,1,1,1,0
access_benefit_behaviors_type,access_benefit_behaviors_type,model_benefit_behaviors_type,,1,1,1,0
access_benefit_expenses,access_benefit_expenses,model_benefit_expenses,,1,1,1,0
access_benefit_cloth,access_benefit_cloth,model_benefit_cloth,,1,1,1,0
access_cloth_type,access_cloth_type,model_cloth_type,,1,1,1,0
access_cloth_size,access_cloth_size,model_cloth_size,,1,1,1,0
access_expenses_line,access_expenses_line,model_expenses_line,,1,1,1,1
access_associations_line,access_associations_line,model_associations_line,,1,1,1,0
access_hospital_hospital,access_hospital_hospital,model_hospital_hospital,,1,1,1,0
access_insurance_type,access_insurance_type,model_insurance_type,,1,1,1,0
access_housing_need,access_housing_need,model_housing_need,,1,1,1,0
access_cars_line,access_cars_line,model_cars_line,,1,1,1,1
access_training_type,access_training_type,model_training_type,,1,1,1,0
access_committees_line,access_committees_line,model_committees_line,,1,1,1,1
access_benefit_followers,access_benefit_followers,model_benefit_followers,,1,1,1,0
access_benefit_record_city_read,access_benefit_record_city_read,model_res_country_city,,1,0,0,0
access_res_districts,access_res_districts,model_res_districts,,1,1,1,1
access_researcher_member_wizard,access_researcher_member_wizard,model_researcher_member_wizard,,1,1,1,1
access_researcher_family_wizard,access_researcher_family_wizard,model_researcher_family_wizard,,1,1,1,1
access_visit_location,access_visit_location,model_visit_location,,1,1,1,1
access_main_service,access_main_service,model_main_service,,1,1,1,1
access_visits_types,access_visits_types,model_visits_types,,1,1,1,1
access_family_member,access_family_member,model_family_member,,1,1,1,1
access_member_location,access_member_location,model_member_location,,1,1,1,1
access_member_disabilities,access_member_disabilities,model_member_disabilities,,1,1,1,1
access_member_diseases,access_member_diseases,model_member_diseases,,1,1,1,1
access_member_hobbies,access_member_hobbies,model_member_hobbies,,1,1,1,1
access_family_debits,access_family_debits,model_family_debits,,1,1,1,1
access_entity_refused_reason_wizard,access_entity_refused_reason_wizard,model_entity_refused_reason_wizard,,1,1,1,1
access_entity_return_reason_wizard,access_entity_return_reason_wizard,model_entity_return_reason_wizard,,1,1,1,1
access_family_validation_setting,access_family_validation_setting,model_family_validation_setting,,1,1,1,1
access_expenses_type,access_expenses_type,model_expenses_type,base.group_user,1,1,1,1
access_survey_setting,access_survey_setting,model_survey_setting,,1,1,1,1
access_changes_requests,access_changes_requests,model_changes_requests,,1,1,1,1
access_entity_black_list_wizard,access_entity_black_list_wizard,model_entity_black_list_wizard,,1,1,1,1
access_education_entities,access_education_entities,model_education_entities,,1,1,1,1
access_education_level,access_education_level,model_education_level,,1,1,1,1
access_education_period,access_education_period,model_education_period,,1,1,1,1
access_education_exam_type,access_education_exam_type,model_education_exam_type,,1,1,1,1
access_family_member_exam,access_family_member_exam,model_family_member_exam,,1,1,1,1
access_education_classroom,access_education_classroom,model_education_classroom,,1,1,1,1
access_education_result,access_education_result,model_education_result,,1,1,1,1
access_study_material,access_study_material,model_study_material,,1,1,1,1
access_suspend_reason,access_suspend_reason,model_suspend_reason,,1,1,1,1
access_suspend_reason_wizard,access_suspend_reason_wizard,model_suspend_reason_wizard,,1,1,1,1
access_expense_family_services_manager,access_expense_family_services_manager,model_confirm_benefit_expense,odex_benefit.group_family_services_manager,1,1,1,1
access_expense_benefit_manager,access_expense_benefit_manager,model_confirm_benefit_expense,odex_benefit.group_benefit_manager,1,1,1,1
access_branch_settings,access_branch_settings,model_branch_settings,base.group_user,1,1,1,1
access_services_settings,access_services_settings,model_services_settings,base.group_user,1,1,1,1
access_rent_lines,access_rent_lines,model_rent_lines,base.group_user,1,1,1,1
access_relation_settings,access_relation_settings,model_relation_settings,,1,1,1,1
access_attachments_settings,access_attachments_settings,model_attachments_settings,base.group_user,1,1,1,1
access_education_illiterate_reason,access_education_illiterate_reason,model_education_illiterate_reason,base.group_user,1,1,1,1
access_education_delay_reason,access_education_delay_reason,model_education_delay_reason,base.group_user,1,1,1,1
access_income_type,access_income_type,model_income_type,base.group_user,1,1,1,1
access_loan_giver,access_loan_giver,model_loan_giver,base.group_user,1,1,1,1
access_loan_reason,access_loan_reason,model_loan_reason,base.group_user,1,1,1,1
access_hobbies_settings,access_hobbies_settings,model_hobbies_settings,base.group_user,1,1,1,1
access_disabilities_settings,access_disabilities_settings,model_disabilities_settings,base.group_user,1,1,1,1
access_diseases_settings,access_diseases_settings,model_diseases_settings,base.group_user,1,1,1,1
access_exception_wizard,access_exception_wizard,model_exception_wizard,base.group_user,1,1,1,1
access_exception_reason,access_exception_reason,model_exception_reason,base.group_user,1,1,1,1
access_service_request,access_service_request,model_service_request,base.group_user,1,1,1,1
access_seasonal_service,access_seasonal_services,model_seasonal_service,base.group_user,1,1,1,1
access_marital_status,access_marital_status,model_marital_status,base.group_user,1,1,1,1
access_service_attachments_settings,access_service_attachments_settings,model_service_attachments_settings,base.group_user,1,1,1,1
access_category_amount_line,access_category_amount_line,model_category_amount_line,base.group_user,1,1,1,1
access_home_maintenance_lines,access_home_maintenance_lines,model_home_maintenance_lines,base.group_user,1,1,1,1
access_home_maintenance_items,access_home_maintenance_items,model_home_maintenance_items,base.group_user,1,1,1,1
access_payment_orders,access_payment_orders,model_payment_orders,base.group_user,1,1,1,1
access_electrical_devices,access_electrical_devices,model_electrical_devices,base.group_user,1,1,1,1
access_home_furnishing_lines,access_home_furnishing_lines,model_home_furnishing_lines,base.group_user,1,1,1,1
access_home_furnishing_items,access_home_furnishing_items,model_home_furnishing_items,base.group_user,1,1,1,1
access_bill_lines,access_bill_lines,model_bill_lines,base.group_user,1,1,1,1
access_age_category,access_age_category,model_age_category,base.group_user,1,1,1,1
access_complaints_category,access_complaints_category,model_complaints_category,base.group_user,1,1,1,1
access_family_complaints,access_family_complaints,model_family_complaints,base.group_user,1,1,1,1
access_service_limit_person_line,access_service_limit_person_line,model_service_limit_person_line,base.group_user,1,1,1,1
access_location_settings,access_location_settings,model_location_settings,base.group_user,1,1,1,1
access_service_refuse_reason,access_service_refuse_reason,model_service_refuse_reason,base.group_user,1,1,1,1
access_service_refuse_reason_wizard,access_service_refuse_reason_wizard,model_service_refuse_reason_wizard,base.group_user,1,1,1,1
access_reason_for_return_wizard,access_reason_for_return_wizard,model_reason_for_return_wizard,base.group_user,1,1,1,1
access_transportation_insurance,access_transportation_insurance,model_transportation_insurance,base.group_user,1,1,1,1
access_job_settings,access_job_settings,model_job_settings,base.group_user,1,0,0,0
access_job_settings_manager,access_job_settings.manager,model_job_settings,odex_benefit.group_benefit_manager,1,1,1,1
access_death_reason_settings,access_death_reason_settings,model_death_reason_settings,base.group_user,1,0,0,0
access_death_reason_settings_manager,access_death_reason_settings.manager,model_death_reason_settings,odex_benefit.group_benefit_manager,1,1,1,1
access_grant_benefit_portal_user,access_grant_benefit_portal_user,model_grant_benefit,base.group_portal,1,1,1,1
access_visit_location_otp_wizard,access_visit_location_otp_wizard,model_visit_location_otp_wizard,,1,1,1,1
access_visit_skip_otp_wizard,access_visit_skip_otp_wizard,model_visit_skip_otp_wizard,,1,1,1,1
access_benefit_vehicle_model,access_benefit_vehicle_model,model_benefit_vehicle_model,,1,1,1,1
access_visit_location_refusal_reason_wizard,access_visit_location_refusal_reason_wizard,model_visit_location_refusal_reason_wizard,,1,1,1,1
access_survey_user_input_group_benefit_info,survey.user_input.group_benefit_info,survey.model_survey_user_input,odex_benefit.group_benefit_info,1,0,0,0
access_survey_user_input_line_group_benefit_info,survey.user_input.line.group_benefit_info,survey.model_survey_user_input_line,odex_benefit.group_benefit_info,1,0,0,0
access_grant_benefit_account_move_line,access_grant_benefit_account_move_line,model_account_move_line,odex_benefit.group_benefit_info,1,0,0,0
access_grant_benefit_account_move,access_grant_benefit_account_move,model_account_move,odex_benefit.group_benefit_info,1,0,0,0
access_benefit_expense_line,access_benefit_expense_line,model_benefit_expense_line,base.group_user,1,1,1,1
access_family_bank_report_wizard,access_family_bank_report_wizard,model_family_bank_report_wizard,base.group_user,1,1,1,1
access_return_reason,access_return_reason,model_return_reason,base.group_user,1,1,1,1
access_return_reason_wizard,access_return_reason_wizard,model_return_reason_wizard,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_benefit_researcher_record access_benefit_researcher_record model_grant_benefit odex_benefit.group_benefit_researcher 1 1 1 0
3 access_benefit_woman_commitee_record access_benefit_record model_grant_benefit odex_benefit.group_benefit_woman_commitee 1 1 1 1
4 access_benefit_branch_manager_record access_benefit_branch_manager_record model_grant_benefit odex_benefit.group_benefit_branch_manager 1 1 1 1
5 access_benefit_manager_record access_benefit_manager_record model_grant_benefit odex_benefit.group_benefit_manager 1 1 1 1
6 access_benefit_edit_record access_benefit_edit_record model_grant_benefit odex_benefit.group_benefit_edit 1 1 1 1
7 access_education_status_all education_status model_education_status odex_benefit.group_benefit_info 1 1 1 1
8 access_education_status_all_users education_status_all_users model_education_status 1 0 0 0
9 access_weak_course_all weak_course model_weak_course odex_benefit.group_benefit_info 1 1 1 1
10 access_benefit_family_record access_benefit_family_record model_benefit_family 1 1 1 0
11 access_benefit_record_city access_benefit_record_city model_res_country_city 1 1 0 0
12 access_benefit_record_reason access_benefit_record_reason model_entity_refuse_reason 1 1 1 0
13 access_benefit_domestic_labor access_domestic_labor model_domestic_labor 1 1 1 1
14 access_benefit_widow_family access_widow_family model_widow_family 1 1 1 1
15 access_benefit_divorcee_family access_divorcee_family model_divorcee_family 1 1 1 1
16 access_external_request access_external_request model_external_request 1 1 1 1
17 access_benefit_food_basket access_benefit_food_basket model_benefit_food_basket 1 1 1 1
18 access_food_basket_line access_food_basket_line model_food_basket_line 1 1 1 1
19 access_benefit_zkat access_benefit_zkat model_benefit_zkat 1 1 1 1
20 access_payment_collection_line access_payment_collection_line model_payment_collection_line 1 1 1 1
21 access_benefit_food_surplus access_benefit_food_surplus model_benefit_food_surplus 1 1 1 1
22 access_food_surplus_line access_food_surplus_line model_food_surplus_line 1 1 1 1
23 access_food_surplus_type access_food_surplus_type model_food_surplus_type 1 1 1 1
24 access_benefit_loans access_benefit_loans model_benefit_loans 1 1 1 1
25 access_appliances_furniture access_appliances_furniture model_appliances_furniture 1 1 1 1
26 access_specialization_specialization access_specialization_specialization model_specialization_specialization 1 1 1 1
27 access_sport_type access_sport_type model_sport_type 1 1 1 1
28 access_insurance_company access_insurance_company model_insurance_company 1 1 1 1
29 access_other_associations access_other_associations model_other_associations 1 1 1 1
30 access_craft_skills access_craft_skills model_craft_skills 1 1 1 1
31 access_training_inclinations access_training_inclinations model_training_inclinations 1 1 1 1
32 access_appliances_furniture_need access_appliances_furniture_need model_appliances_furniture_need 1 1 1 1
33 access_salary_line access_salary_line model_salary_line 1 1 1 1
34 access_benefit_club access_benefit_club model_benefit_club 1 1 1 1
35 access_benefit_programs access_benefit_programs model_benefit_programs 1 1 1 1
36 access_benefit_housing access_benefit_housing model_benefit_housing 1 1 0 0
37 access_benefit_housing access_benefit_housing model_benefit_housing 1 1 1 1
38 access_benefit_housing_rooms access_benefit_housing_rooms model_benefit_housing_rooms 1 1 1 1
39 access_benefit_housing_rooms_items access_benefit_housing_rooms_items model_benefit_housing_rooms_items 1 1 1 1
40 access_housing_rooms_type access_housing_rooms_type model_housing_rooms_type 1 1 1 1
41 access_rooms_items access_rooms_items model_rooms_items 1 1 1 1
42 access_item_status access_item_status model_item_status 1 1 1 1
43 access_rooms_categories access_rooms_categories model_rooms_categories 1 1 1 1
44 access_housing_rooms_members access_housing_rooms_members model_housing_rooms_members 1 1 1 1
45 access_item_status access_item_status model_item_status 1 1 1 1
46 access_generate_reports access_generate_reports model_generate_reports 1 1 1 1
47 access_food_basket_benefits_line access_food_basket_benefits_line model_food_basket_benefits_line 1 1 1 1
48 access_benefit_family_record_officer access_benefit_family_record_officer model_benefit_family 1 1 1 1
49 access_benefit_record_city_officer access_benefit_record_city_officer model_res_country_city 1 1 1 1
50 access_external_benefits access_external_benefits model_external_benefits 1 1 1 0
51 access_benefits_representative access_benefits_representative model_benefits_representative 1 1 1 0
52 access_benefits_needs access_benefits_needs model_benefits_needs 1 1 1 0
53 access_needs_payment_line access_needs_payment_line model_needs_payment_line 1 1 1 0
54 access_needs_categories access_needs_categories model_needs_categories 1 1 1 0
55 access_benefit_need access_benefit_need model_benefit_need 1 1 1 0
56 access_house_need access_house_need model_house_need 1 1 1 0
57 access_generate_reports_log access_generate_reports_log model_generate_reports_log 1 1 1 0
58 access_program_plane_line access_program_plane_line model_program_plane_line 1 1 1 0
59 access_benefit_club_activity access_benefit_club_activity model_benefit_club_activity 1 1 1 0
60 access_receive_benefit_loans access_receive_benefit_loans model_receive_benefit_loans 1 1 1 0
61 access_purchase_product_loan access_purchase_product_loan model_purchase_product_loan 1 1 1 0
62 access_receive_food_surplus access_receive_food_surplus model_receive_food_surplus 1 1 1 0
63 access_receive_appliances_furniture access_receive_appliances_furniture model_receive_appliances_furniture 1 1 1 0
64 access_donations_type access_donations_type model_donations_type 1 1 1 0
65 access_receive_benefit_zkat access_receive_benefit_zkat model_receive_benefit_zkat 1 1 1 0
66 access_zkat_line access_zkat_line model_zkat_line 1 1 1 0
67 access_benefit_zkat_line access_benefit_zkat_line model_benefit_zkat_line 1 1 1 0
68 access_receive_food_basket access_receive_food_basket model_receive_food_basket 1 1 1 0
69 access_benefit_sms_configuration access_benefit_sms_configuration model_benefit_sms_configuration 1 1 1 0
70 access_benefit_category access_benefit_category model_benefit_category 1 1 1 1
71 access_sport_line access_sport_line model_sport_line 1 1 1 0
72 access_benefit_behaviors access_benefit_behaviors model_benefit_behaviors 1 1 1 0
73 access_benefit_behaviors_type access_benefit_behaviors_type model_benefit_behaviors_type 1 1 1 0
74 access_benefit_expenses access_benefit_expenses model_benefit_expenses 1 1 1 0
75 access_benefit_cloth access_benefit_cloth model_benefit_cloth 1 1 1 0
76 access_cloth_type access_cloth_type model_cloth_type 1 1 1 0
77 access_cloth_size access_cloth_size model_cloth_size 1 1 1 0
78 access_expenses_line access_expenses_line model_expenses_line 1 1 1 1
79 access_associations_line access_associations_line model_associations_line 1 1 1 0
80 access_hospital_hospital access_hospital_hospital model_hospital_hospital 1 1 1 0
81 access_insurance_type access_insurance_type model_insurance_type 1 1 1 0
82 access_housing_need access_housing_need model_housing_need 1 1 1 0
83 access_cars_line access_cars_line model_cars_line 1 1 1 1
84 access_training_type access_training_type model_training_type 1 1 1 0
85 access_committees_line access_committees_line model_committees_line 1 1 1 1
86 access_benefit_followers access_benefit_followers model_benefit_followers 1 1 1 0
87 access_benefit_record_city_read access_benefit_record_city_read model_res_country_city 1 0 0 0
88 access_res_districts access_res_districts model_res_districts 1 1 1 1
89 access_researcher_member_wizard access_researcher_member_wizard model_researcher_member_wizard 1 1 1 1
90 access_researcher_family_wizard access_researcher_family_wizard model_researcher_family_wizard 1 1 1 1
91 access_visit_location access_visit_location model_visit_location 1 1 1 1
92 access_main_service access_main_service model_main_service 1 1 1 1
93 access_visits_types access_visits_types model_visits_types 1 1 1 1
94 access_family_member access_family_member model_family_member 1 1 1 1
95 access_member_location access_member_location model_member_location 1 1 1 1
96 access_member_disabilities access_member_disabilities model_member_disabilities 1 1 1 1
97 access_member_diseases access_member_diseases model_member_diseases 1 1 1 1
98 access_member_hobbies access_member_hobbies model_member_hobbies 1 1 1 1
99 access_family_debits access_family_debits model_family_debits 1 1 1 1
100 access_entity_refused_reason_wizard access_entity_refused_reason_wizard model_entity_refused_reason_wizard 1 1 1 1
101 access_entity_return_reason_wizard access_entity_return_reason_wizard model_entity_return_reason_wizard 1 1 1 1
102 access_family_validation_setting access_family_validation_setting model_family_validation_setting 1 1 1 1
103 access_expenses_type access_expenses_type model_expenses_type base.group_user 1 1 1 1
104 access_survey_setting access_survey_setting model_survey_setting 1 1 1 1
105 access_changes_requests access_changes_requests model_changes_requests 1 1 1 1
106 access_entity_black_list_wizard access_entity_black_list_wizard model_entity_black_list_wizard 1 1 1 1
107 access_education_entities access_education_entities model_education_entities 1 1 1 1
108 access_education_level access_education_level model_education_level 1 1 1 1
109 access_education_period access_education_period model_education_period 1 1 1 1
110 access_education_exam_type access_education_exam_type model_education_exam_type 1 1 1 1
111 access_family_member_exam access_family_member_exam model_family_member_exam 1 1 1 1
112 access_education_classroom access_education_classroom model_education_classroom 1 1 1 1
113 access_education_result access_education_result model_education_result 1 1 1 1
114 access_study_material access_study_material model_study_material 1 1 1 1
115 access_suspend_reason access_suspend_reason model_suspend_reason 1 1 1 1
116 access_suspend_reason_wizard access_suspend_reason_wizard model_suspend_reason_wizard 1 1 1 1
117 access_expense_family_services_manager access_expense_family_services_manager model_confirm_benefit_expense odex_benefit.group_family_services_manager 1 1 1 1
118 access_expense_benefit_manager access_expense_benefit_manager model_confirm_benefit_expense odex_benefit.group_benefit_manager 1 1 1 1
119 access_branch_settings access_branch_settings model_branch_settings base.group_user 1 1 1 1
120 access_services_settings access_services_settings model_services_settings base.group_user 1 1 1 1
121 access_rent_lines access_rent_lines model_rent_lines base.group_user 1 1 1 1
122 access_relation_settings access_relation_settings model_relation_settings 1 1 1 1
123 access_attachments_settings access_attachments_settings model_attachments_settings base.group_user 1 1 1 1
124 access_education_illiterate_reason access_education_illiterate_reason model_education_illiterate_reason base.group_user 1 1 1 1
125 access_education_delay_reason access_education_delay_reason model_education_delay_reason base.group_user 1 1 1 1
126 access_income_type access_income_type model_income_type base.group_user 1 1 1 1
127 access_loan_giver access_loan_giver model_loan_giver base.group_user 1 1 1 1
128 access_loan_reason access_loan_reason model_loan_reason base.group_user 1 1 1 1
129 access_hobbies_settings access_hobbies_settings model_hobbies_settings base.group_user 1 1 1 1
130 access_disabilities_settings access_disabilities_settings model_disabilities_settings base.group_user 1 1 1 1
131 access_diseases_settings access_diseases_settings model_diseases_settings base.group_user 1 1 1 1
132 access_exception_wizard access_exception_wizard model_exception_wizard base.group_user 1 1 1 1
133 access_exception_reason access_exception_reason model_exception_reason base.group_user 1 1 1 1
134 access_service_request access_service_request model_service_request base.group_user 1 1 1 1
135 access_seasonal_service access_seasonal_services model_seasonal_service base.group_user 1 1 1 1
136 access_marital_status access_marital_status model_marital_status base.group_user 1 1 1 1
137 access_service_attachments_settings access_service_attachments_settings model_service_attachments_settings base.group_user 1 1 1 1
138 access_category_amount_line access_category_amount_line model_category_amount_line base.group_user 1 1 1 1
139 access_home_maintenance_lines access_home_maintenance_lines model_home_maintenance_lines base.group_user 1 1 1 1
140 access_home_maintenance_items access_home_maintenance_items model_home_maintenance_items base.group_user 1 1 1 1
141 access_payment_orders access_payment_orders model_payment_orders base.group_user 1 1 1 1
142 access_electrical_devices access_electrical_devices model_electrical_devices base.group_user 1 1 1 1
143 access_home_furnishing_lines access_home_furnishing_lines model_home_furnishing_lines base.group_user 1 1 1 1
144 access_home_furnishing_items access_home_furnishing_items model_home_furnishing_items base.group_user 1 1 1 1
145 access_bill_lines access_bill_lines model_bill_lines base.group_user 1 1 1 1
146 access_age_category access_age_category model_age_category base.group_user 1 1 1 1
147 access_complaints_category access_complaints_category model_complaints_category base.group_user 1 1 1 1
148 access_family_complaints access_family_complaints model_family_complaints base.group_user 1 1 1 1
149 access_service_limit_person_line access_service_limit_person_line model_service_limit_person_line base.group_user 1 1 1 1
150 access_location_settings access_location_settings model_location_settings base.group_user 1 1 1 1
151 access_service_refuse_reason access_service_refuse_reason model_service_refuse_reason base.group_user 1 1 1 1
152 access_service_refuse_reason_wizard access_service_refuse_reason_wizard model_service_refuse_reason_wizard base.group_user 1 1 1 1
153 access_reason_for_return_wizard access_reason_for_return_wizard model_reason_for_return_wizard base.group_user 1 1 1 1
154 access_transportation_insurance access_transportation_insurance model_transportation_insurance base.group_user 1 1 1 1
155 access_job_settings access_job_settings model_job_settings base.group_user 1 0 0 0
156 access_job_settings_manager access_job_settings.manager model_job_settings odex_benefit.group_benefit_manager 1 1 1 1
157 access_death_reason_settings access_death_reason_settings model_death_reason_settings base.group_user 1 0 0 0
158 access_death_reason_settings_manager access_death_reason_settings.manager model_death_reason_settings odex_benefit.group_benefit_manager 1 1 1 1
159 access_grant_benefit_portal_user access_grant_benefit_portal_user model_grant_benefit base.group_portal 1 1 1 1
160 access_visit_location_otp_wizard access_visit_location_otp_wizard model_visit_location_otp_wizard 1 1 1 1
161 access_visit_skip_otp_wizard access_visit_skip_otp_wizard model_visit_skip_otp_wizard 1 1 1 1
162 access_benefit_vehicle_model access_benefit_vehicle_model model_benefit_vehicle_model 1 1 1 1
163 access_visit_location_refusal_reason_wizard access_visit_location_refusal_reason_wizard model_visit_location_refusal_reason_wizard 1 1 1 1
164 access_survey_user_input_group_benefit_info survey.user_input.group_benefit_info survey.model_survey_user_input odex_benefit.group_benefit_info 1 0 0 0
165 access_survey_user_input_line_group_benefit_info survey.user_input.line.group_benefit_info survey.model_survey_user_input_line odex_benefit.group_benefit_info 1 0 0 0
166 access_grant_benefit_account_move_line access_grant_benefit_account_move_line model_account_move_line odex_benefit.group_benefit_info 1 0 0 0
167 access_grant_benefit_account_move access_grant_benefit_account_move model_account_move odex_benefit.group_benefit_info 1 0 0 0
168 access_benefit_expense_line access_benefit_expense_line model_benefit_expense_line base.group_user 1 1 1 1
169 access_family_bank_report_wizard access_family_bank_report_wizard model_family_bank_report_wizard base.group_user 1 1 1 1
170 access_return_reason access_return_reason model_return_reason base.group_user 1 1 1 1
171 access_return_reason_wizard access_return_reason_wizard model_return_reason_wizard base.group_user 1 1 1 1

View File

@ -0,0 +1,349 @@
<odoo>
<data noupdate="0">
<record model="ir.module.category" id="module_category_benefit">
<field name="name">Beneficiaries Management</field>
<field name="description">Helps you manage Beneficiaries Program</field>
<field name="sequence">1</field>
</record>
<!-- record <record id="translation_benefit_ar" model="ir.translation">-->
<!-- <field name="name">ir.module.category,name</field>-->
<!-- <field name="lang">ar_001</field>-->
<!-- <field name="type">model</field>-->
<!-- <field name="res_id" eval="ref('module_category_benefit')"/>-->
<!-- <field name="src">Beneficiaries Management</field>-->
<!-- <field name="value">فئات المستفيدين</field>-->
<!-- </record>-->
<!-- <record id="group_benefit_user" model="res.groups">-->
<!-- <field name="name">Beneficiaries User</field>-->
<!-- <field name="category_id" ref="module_category_benefit"/>-->
<!-- <field name="users" eval="[(4, ref('base.user_root'))]"/>-->
<!--&lt;!&ndash; <field name="implied_ids" eval="[(4, ref('base.group_erp_manager'))]"/>&ndash;&gt;-->
<!-- </record>-->
<record id="group_benefit_info" model="res.groups">
<field name="name">Beneficiaries Inforamtion</field>
<field name="category_id" ref="module_category_benefit"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
<field name="comment">the user will be able to approve Beneficiaries requests.</field>
</record>
<record id="group_benefit_back_to_draft" model="res.groups">
<field name="name">Return Benefit Profile to Draft</field>
<field name="category_id" ref="module_category_benefit"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
<field name="comment">Allows the user to return a benefit profile to draft status.</field>
</record>
<record id="group_benefit_show_draft_record" model="res.groups">
<field name="name">Show Draft Records</field>
<field name="category_id" ref="module_category_benefit"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
</record>
<record id="group_benefit_edit" model="res.groups">
<field name="name">Beneficiaries Edit User</field>
<field name="category_id" ref="module_category_benefit"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
<field name="implied_ids" eval="[(4, ref('group_benefit_info'))]"/>
</record>
<!-- <record id="group_benefit_officer" model="res.groups">-->
<!-- <field name="name">Beneficiaries Officer</field>-->
<!-- <field name="category_id" ref="module_category_benefit"/>-->
<!-- <field name="users" eval="[(4, ref('base.user_root'))]"/>-->
<!-- <field name="implied_ids" eval="[(4, ref('group_benefit_user')),(4, ref('group_benefit_edit'))]"/>-->
<!-- </record>-->
<record id="group_benefit_manager" model="res.groups">
<field name="name">Beneficiaries Manager</field>
<field name="category_id" ref="module_category_benefit"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
<field name="implied_ids" eval="[(4, ref('group_benefit_info'))]"/>
<field name="comment">the user will be able to approve Beneficiaries requests.</field>
</record>
<record id="group_approval_of_beneficiary_services" model="res.groups">
<field name="name">Approval Of Beneficiary Services</field>
<field name="category_id" ref="module_category_benefit"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
<field name="comment">the user will be able to approve Beneficiaries Services.</field>
</record>
<record id="group_benefit_researcher" model="res.groups">
<field name="name">Beneficiaries Researcher</field>
<field name="category_id" ref="module_category_benefit"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
<field name="implied_ids" eval="[(4, ref('group_benefit_info'))]"/>
</record>
<record id="group_benefit_supervisor" model="res.groups">
<field name="name">Researcher Supervisor</field>
<field name="category_id" ref="module_category_benefit"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
<field name="implied_ids" eval="[(4, ref('group_benefit_researcher'))]"/>
</record>
<record id="group_benefit_woman_commitee" model="res.groups">
<field name="name">Head of the Women's Committee</field>
<field name="category_id" ref="module_category_benefit"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
<field name="implied_ids" eval="[(4, ref('group_benefit_info'))]"/>
</record>
<record id="group_benefit_branch_manager" model="res.groups">
<field name="name">Branch Manager</field>
<field name="category_id" ref="module_category_benefit"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
<field name="implied_ids" eval="[(4, ref('group_benefit_info'))]"/>
</record>
<record id="group_benefit_requests_manager" model="res.groups">
<field name="name">Requests Manager</field>
<field name="category_id" ref="module_category_benefit"/>
<field name="implied_ids" eval="[(4, ref('group_benefit_branch_manager'))]"/>
</record>
<record id="group_benefit_accounting_accept" model="res.groups">
<field name="name">Accounting Accept</field>
<field name="category_id" ref="module_category_benefit"/>
<!-- <field name="implied_ids" eval="[(4, ref('group_benefit_info'))]"/>-->
</record>
<record id="group_benefit_bank_info" model="res.groups">
<field name="name">Bank Account Information</field>
<field name="category_id" ref="module_category_benefit"/>
<field name="implied_ids" eval="[(4, ref('group_benefit_info'))]"/>
</record>
<record id="group_benefit_accountant_accept" model="res.groups">
<field name="name">Service Request Accountant Accept</field>
<field name="category_id" ref="odex25_account_payment_fix.module_category_payment_access"/>
<!-- <field name="implied_ids" eval="[(4, ref('group_benefit_info'))]"/>-->
</record>
<record id="group_benefit_payment_accountant_accept" model="res.groups">
<field name="name">Payment Orders Accountant Accept</field>
<field name="category_id" ref="odex25_account_payment_fix.module_category_payment_access"/>
<!-- <field name="implied_ids" eval="[(4, ref('group_benefit_info'))]"/>-->
</record>
<record id="group_accept_income_and_expenses" model="res.groups">
<field name="name">Accept income and expenses</field>
<field name="category_id" ref="module_category_benefit"/>
</record>
<record id="group_otp_manager" model="res.groups">
<field name="name">OTP Manager</field>
<field name="category_id" ref="module_category_benefit"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
</record>
<record id="group_family_service_receipt" model="res.groups">
<field name="name">Family Service Receipt</field>
<field name="category_id" ref="module_category_benefit"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
</record>
<record id="group_family_services_manager" model="res.groups">
<field name="name">Family Services Manager</field>
<field name="category_id" ref="module_category_benefit"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
<field name="implied_ids" eval="[(4, ref('group_benefit_manager'))]"/>
</record>
<record id="group_service_legal_department" model="res.groups">
<field name="name">Services - Legal Department</field>
<field name="category_id" ref="module_category_benefit"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
</record>
<record id="group_service_projects_department" model="res.groups">
<field name="name">Services - Projects Department</field>
<field name="category_id" ref="module_category_benefit"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
</record>
<!-- Add rules for grant.benefit -->
<record id="grant_benefit_show_all_rule" model="ir.rule">
<field name="name">Show All Benefits Profiles</field>
<field name="model_id" ref="model_grant_benefit"/>
<field name="domain_force">[(1, '=', 1)]</field>
<field name="groups" eval="[(4, ref('group_benefit_manager')),(4, ref('group_benefit_supervisor'))]"/>
<field name="active" eval="True" />
</record>
<record id="grant_benefit_rule_branch_manager" model="ir.rule">
<field name="name">Show Benefits Profiles of Own Branch</field>
<field name="model_id" ref="model_grant_benefit"/>
<field name="domain_force">[('branch_custom_id.branch.manager_id', '=', user.employee_id.id)]</field>
<field name="groups" eval="[(4, ref('group_benefit_branch_manager'))]"/>
<field name="active" eval="True" />
</record>
<record id="grant_benefit_rule_operation_manager" model="ir.rule">
<field name="name">Show Benefits Profiles of Assigned Branch (Operation Manager)</field>
<field name="model_id" ref="model_grant_benefit"/>
<field name="domain_force">[('branch_custom_id.branch.operation_manager_id', '=', user.employee_id.id)]</field>
<field name="groups" eval="[(4, ref('group_benefit_woman_commitee'))]"/>
<field name="active" eval="True" />
</record>
<record id="grant_benefit_rule_researcher" model="ir.rule">
<field name="name">Show Benefits Profiles Created or Assigned (Researcher)</field>
<field name="model_id" ref="model_grant_benefit"/>
<field name="domain_force">['|', ('create_uid','=',user.id),('researcher_id.employee_id', 'in', user.employee_id.ids)]</field>
<field name="groups" eval="[(4, ref('group_benefit_researcher'))]"/>
<field name="active" eval="True" />
</record>
<!-- Add rules for visit.location -->
<record id="visit_location_show_all_rule" model="ir.rule">
<field name="name">Show All Visit Location</field>
<field name="model_id" ref="model_visit_location"/>
<field name="domain_force">[(1, '=', 1)]</field>
<field name="groups" eval="[(4, ref('group_benefit_manager')),(4, ref('group_benefit_supervisor'))]"/>
<field name="active" eval="True" />
</record>
<record id="visit_location_rule_branch_manager" model="ir.rule">
<field name="name">Show Visit Location of Own Branch</field>
<field name="model_id" ref="model_visit_location"/>
<field name="domain_force">[('benefit_id.branch_custom_id.branch.manager_id', '=', user.employee_id.id)]</field>
<field name="groups" eval="[(4, ref('group_benefit_branch_manager'))]"/>
<field name="active" eval="True" />
</record>
<record id="visit_location_rule_operation_manager" model="ir.rule">
<field name="name">Show Visit Location of Assigned Branch (Operation Manager)</field>
<field name="model_id" ref="model_visit_location"/>
<field name="domain_force">[('benefit_id.branch_custom_id.branch.operation_manager_id', '=', user.employee_id.id)]</field>
<field name="groups" eval="[(4, ref('group_benefit_woman_commitee'))]"/>
<field name="active" eval="True" />
</record>
<record id="visit_location_rule_researcher" model="ir.rule">
<field name="name">Show Visit Location Created or Assigned (Researcher)</field>
<field name="model_id" ref="model_visit_location"/>
<field name="domain_force">[
'|',
('create_uid','=',user.id),
('researcher_team.employee_id', 'in', user.employee_id.ids)
]</field>
<field name="groups" eval="[(4, ref('group_benefit_researcher'))]"/>
<field name="active" eval="True" />
</record>
<record id="survey_user_input_rule_group_benefit_info" model="ir.rule">
<field name="name">Survey user input: Group Benefit Info</field>
<field name="model_id" ref="survey.model_survey_user_input"/>
<field name="domain_force">[(1, '=', 1)]</field>
<field name="groups" eval="[(4, ref('odex_benefit.group_benefit_info'))]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
</record>
<!-- Add rules for family.complaints -->
<record id="family_complaints_show_all_rule" model="ir.rule">
<field name="name">Show All Family Complaints</field>
<field name="model_id" ref="model_family_complaints"/>
<field name="domain_force">[(1, '=', 1)]</field>
<field name="groups" eval="[(4, ref('group_benefit_manager')),(4, ref('group_benefit_supervisor'))]"/>
<field name="active" eval="True" />
</record>
<record id="family_complaints_rule_branch_manager" model="ir.rule">
<field name="name">Show Family Complaints of Own Branch</field>
<field name="model_id" ref="model_family_complaints"/>
<field name="domain_force">[('branch_custom_id.branch.manager_id', '=', user.employee_id.id)]</field>
<field name="groups" eval="[(4, ref('group_benefit_branch_manager'))]"/>
<field name="active" eval="True" />
</record>
<record id="family_complaints_rule_operation_manager" model="ir.rule">
<field name="name">Show Family Complaints of Assigned Branch (Operation Manager)</field>
<field name="model_id" ref="model_family_complaints"/>
<field name="domain_force">[('branch_custom_id.branch.operation_manager_id', '=', user.employee_id.id)]</field>
<field name="groups" eval="[(4, ref('group_benefit_woman_commitee'))]"/>
<field name="active" eval="True" />
</record>
<record id="family_complaints_rule_researcher" model="ir.rule">
<field name="name">Show Family Complaints Created or Assigned (Researcher)</field>
<field name="model_id" ref="model_family_complaints"/>
<field name="domain_force">[
'|',
('create_uid','=',user.id),
('researcher_id.employee_id', 'in', user.employee_id.ids)
]</field>
<field name="groups" eval="[(4, ref('group_benefit_researcher'))]"/>
<field name="active" eval="True" />
</record>
<!-- Add rules for service.request -->
<record id="service_request_restrict_all_requests_by_rule" model="ir.rule">
<field name="name">Show All Service Requests</field>
<field name="model_id" ref="model_service_request"/>
<field name="domain_force">[(1, '=', 1)]</field>
<field name="groups" eval="[(4, ref('group_benefit_requests_manager')),(4, ref('group_benefit_supervisor')),(4, ref('group_benefit_accountant_accept')),(4, ref('group_benefit_payment_accountant_accept'))]"/>
<field name="active" eval="True"/>
</record>
<record id="service_request_restrict_only_created_by_rule" model="ir.rule">
<field name="name">Show Service Requests That Own</field>
<field name="model_id" ref="model_service_request"/>
<field name="domain_force">[
'|',
('create_uid','=',user.id),
('researcher_id.employee_id', 'in', user.employee_id.ids)
]</field>
<field name="groups" eval="[(4, ref('group_benefit_researcher'))]"/>
<field name="active" eval="True" />
</record>
<record id="service_request_restrict_only_his_branch_rule" model="ir.rule">
<field name="name">Show Service Requests That Own</field>
<field name="model_id" ref="model_service_request"/>
<field name="domain_force">[
'|',
('family_id.branch_custom_id.branch.manager_id', '=', user.employee_id.id),
('family_id.branch_custom_id.branch.operation_manager_id', '=', user.employee_id.id)
]</field>
<field name="groups" eval="[(4, ref('group_benefit_branch_manager')), (4, ref('group_benefit_woman_commitee'))]"/>
<field name="active" eval="True" />
</record>
<record id="service_request_rule_legal_department" model="ir.rule">
<field name="name">Service Requests - Legal Department</field>
<field name="model_id" ref="model_service_request"/>
<field name="groups" eval="[(4, ref('odex_benefit.group_service_legal_department'))]"/>
<field name="domain_force">[('service_cat.needs_legal_approval', '=', True)]</field>
<field name="active" eval="True"/>
</record>
<!-- Add rules for family.member -->
<record id="family_member_show_all_rule" model="ir.rule">
<field name="name">Show All Family Members</field>
<field name="model_id" ref="model_family_member"/>
<field name="domain_force">[(1, '=', 1)]</field>
<field name="groups" eval="[(4, ref('group_benefit_manager')),(4, ref('group_benefit_supervisor'))]"/>
<field name="active" eval="True" />
</record>
<record id="family_member_rule_branch_manager" model="ir.rule">
<field name="name">Show Family Members of Own Branch</field>
<field name="model_id" ref="model_family_member"/>
<field name="domain_force">[('benefit_id.branch_custom_id.branch.manager_id', '=', user.employee_id.id)]</field>
<field name="groups" eval="[(4, ref('group_benefit_branch_manager'))]"/>
<field name="active" eval="True" />
</record>
<record id="family_member_rule_operation_manager" model="ir.rule">
<field name="name">Show Family Members of Assigned Branch (Operations Manager)</field>
<field name="model_id" ref="model_family_member"/>
<field name="domain_force">[('benefit_id.branch_custom_id.branch.operation_manager_id', '=', user.employee_id.id)]</field>
<field name="groups" eval="[(4, ref('group_benefit_woman_commitee'))]"/>
<field name="active" eval="True" />
</record>
<record id="family_member_rule_researcher" model="ir.rule">
<field name="name">Show Family Members Created or Assigned (Researcher)</field>
<field name="model_id" ref="model_family_member"/>
<field name="domain_force">['|', ('create_uid','=',user.id),('benefit_id.researcher_id.employee_id', 'in', user.employee_id.ids)]</field>
<field name="groups" eval="[(4, ref('group_benefit_researcher'))]"/>
<field name="active" eval="True" />
</record>
</data>
</odoo>

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Some files were not shown because too many files have changed in this diff Show More