From 432ae2c303b36babf689d500749f45b3f1ea081d Mon Sep 17 00:00:00 2001 From: expert Date: Mon, 24 Jun 2024 14:17:49 +0300 Subject: [PATCH] Add odex25_project --- README.md | 2 +- odex25_project/kpi_scorecard_odex/__init__.py | 6 + .../kpi_scorecard_odex/__manifest__.py | 35 + .../kpi_scorecard_odex/i18n/ar_001.po | 1999 ++++++++++++++ .../kpi_scorecard_odex/models/__init__.py | 13 + .../kpi_scorecard_odex/models/kpi_category.py | 35 + .../kpi_scorecard_odex/models/kpi_item.py | 128 + .../kpi_scorecard_odex/models/kpi_period.py | 111 + .../models/kpi_scorecard_line.py | 216 ++ .../models/partner_target.py | 11 + .../kpi_scorecard_odex/reports/__init__.py | 1 + .../security/ir.model.access.csv | 2 + .../kpi_scorecard_odex/views/kpi_category.xml | 38 + .../kpi_scorecard_odex/views/kpi_item.xml | 253 ++ .../views/kpi_scorecard_line.xml | 145 + .../views/menu_security_cus.xml | 7 + .../odex25_helpdesk_sale/__init__.py | 3 + .../odex25_helpdesk_sale/__manifest__.py | 18 + .../data/odex25_helpdesk_sale_demo.xml | 53 + .../odex25_helpdesk_sale/i18n/ar.po | 59 + .../odex25_helpdesk_sale/models/__init__.py | 3 + .../models/odex25_helpdesk.py | 23 + .../static/description/icon.png | Bin 0 -> 32929 bytes .../views/odex25_helpdesk_views.xml | 44 + .../odex25_helpdesk_timesheet/__init__.py | 15 + .../odex25_helpdesk_timesheet/__manifest__.py | 24 + .../data/odex25_helpdesk_timesheet_data.xml | 12 + .../data/odex25_helpdesk_timesheet_demo.xml | 25 + .../odex25_helpdesk_timesheet/i18n/ar.po | 404 +++ .../models/__init__.py | 5 + .../models/analytic.py | 45 + .../models/odex25_helpdesk.py | 253 ++ .../models/project.py | 30 + .../security/ir.model.access.csv | 6 + .../odex25_helpdesk_timesheet_security.xml | 26 + .../static/description/icon.png | Bin 0 -> 32929 bytes .../tests/__init__.py | 4 + .../tests/test_project.py | 111 + .../views/odex25_helpdesk_views.xml | 189 ++ .../views/project_views.xml | 47 + .../wizard/__init__.py | 3 + ...odex25_helpdesk_ticket_create_timesheet.py | 38 + ...helpdesk_ticket_create_timesheet_views.xml | 22 + .../inspectionProfiles/profiles_settings.xml | 6 + odex25_project/project_base/.idea/misc.xml | 4 + odex25_project/project_base/.idea/modules.xml | 8 + .../project_base/.idea/project_base.iml | 8 + .../project_base/.idea/workspace.xml | 36 + odex25_project/project_base/__init__.py | 4 + odex25_project/project_base/__manifest__.py | 34 + .../project_base/data/project_cron.xml | 26 + .../project_base/data/project_data.xml | 16 + odex25_project/project_base/i18n/ar.po | 48 + odex25_project/project_base/i18n/ar_001.po | 2142 +++++++++++++++ .../project_base/models/__init__.py | 9 + odex25_project/project_base/models/project.py | 563 ++++ .../project_base/models/project_invoice.py | 395 +++ .../project_base/models/project_phase.py | 196 ++ .../project_base/models/project_task.py | 63 + .../project_base/models/res_company.py | 22 + .../project_base/models/res_config_setting.py | 17 + .../project_base/models/sale_order.py | 54 + .../project_invoice_report_templates.xml | 156 ++ .../report/project_report_templates.xml | 167 ++ .../project_base/report/project_reports.xml | 34 + .../project_base/security/ir.model.access.csv | 23 + .../security/ir_rule_allow_users.xml | 63 + .../security/project_security.xml | 157 ++ .../static/src/css/progress_bar_color.css | 16 + .../static/src/js/progress_bar_color.js | 48 + odex25_project/project_base/views/asset.xml | 11 + .../views/project_invoice_views.xml | 191 ++ .../project_base/views/project_phase_view.xml | 169 ++ .../project_base/views/project_task_views.xml | 169 ++ .../project_base/views/project_views.xml | 728 +++++ .../project_base/views/res_config_setting.xml | 122 + .../project_base/wizard/__init__.py | 5 + .../wizard/down_payment_invoice_advance.py | 27 + .../down_payment_invoice_advance_views.xml | 16 + .../project_base/wizard/edit_project_phase.py | 43 + .../wizard/edit_project_phase_view.xml | 48 + .../wizard/project_hold_reason.py | 27 + .../wizard/project_hold_reason_view.xml | 39 + odex25_project/project_budget/__init__.py | 1 + odex25_project/project_budget/__manifest__.py | 22 + odex25_project/project_budget/i18n/ar_001.po | 438 +++ .../project_budget/models/__init__.py | 3 + .../project_budget/models/account_budget.py | 248 ++ .../project_budget/models/project.py | 91 + .../security/account_budget_security.xml | 31 + .../security/ir.model.access.csv | 6 + .../static/description/icon.png | Bin 0 -> 32929 bytes odex25_project/project_budget/views/view.xml | 343 +++ .../project_customer_team/__init__.py | 4 + .../project_customer_team/__manifest__.py | 17 + .../project_customer_team/i18n/ar_001.po | 92 + .../project_customer_team/models/__init__.py | 4 + .../project_customer_team/models/project.py | 19 + .../security/ir.model.access.csv | 2 + .../views/project_views.xml | 26 + .../project_helpdisk_task/__init__.py | 4 + .../project_helpdisk_task/__manifest__.py | 16 + .../project_helpdisk_task/models/__init__.py | 5 + .../project_helpdisk_task/models/project.py | 11 + .../models/project_task.py | 16 + .../views/project_task_views.xml | 23 + .../views/project_views.xml | 17 + odex25_project/project_maps/__init__.py | 1 + odex25_project/project_maps/__manifest__.py | 19 + odex25_project/project_maps/i18n/ar_001.po | 103 + .../project_maps/models/__init__.py | 1 + .../project_maps/models/project_project.py | 47 + .../views/project_project_view.xml | 107 + odex25_project/project_metrics/__init__.py | 2 + .../project_metrics/__manifest__.py | 19 + .../project_metrics/models/__init__.py | 3 + .../project_metrics/models/project_metrics.py | 104 + .../project_metrics/models/project_project.py | 69 + .../project_metrics/models/project_task.py | 142 + .../security/ir.model.access.csv | 3 + .../views/project_metrics_views.xml | 68 + .../views/project_project_views.xml | 24 + .../views/project_task_views.xml | 141 + odex25_project/project_native/__init__.py | 5 + odex25_project/project_native/__manifest__.py | 43 + .../project_native/doc/RELEASE_NOTES.md | 48 + odex25_project/project_native/doc/index.rst | 49 + odex25_project/project_native/i18n/ar_001.po | 315 +++ .../images/gantt_native_view.png | Bin 0 -> 436843 bytes .../project_native/models/__init__.py | 12 + .../project_native/models/project_task.py | 570 ++++ .../models/project_task_calendar.py | 633 +++++ .../models/project_task_critical_path.py | 66 + .../models/project_task_detail_plan.py | 132 + .../models/project_task_info.py | 53 + .../models/project_task_resource.py | 129 + .../models/project_task_scheduler.py | 897 +++++++ .../models/project_task_scheduler_calendar.py | 170 ++ .../models/project_task_tree.py | 68 + .../models/project_task_tree_update.py | 98 + .../project_native/models/resource.py | 12 + .../security/ir.model.access.csv | 6 + .../project_native/static/description/A1.png | Bin 0 -> 82040 bytes .../project_native/static/description/A2.png | Bin 0 -> 45034 bytes .../project_native/static/description/A3.png | Bin 0 -> 73339 bytes .../project_native/static/description/G01.png | Bin 0 -> 436843 bytes .../project_native/static/description/G02.png | Bin 0 -> 29792 bytes .../project_native/static/description/G03.png | Bin 0 -> 35000 bytes .../project_native/static/description/G04.png | Bin 0 -> 6762 bytes .../project_native/static/description/G05.png | Bin 0 -> 90505 bytes .../project_native/static/description/G06.png | Bin 0 -> 7438 bytes .../project_native/static/description/G07.png | Bin 0 -> 3310 bytes .../project_native/static/description/G09.png | Bin 0 -> 6801 bytes .../project_native/static/description/G10.png | Bin 0 -> 8443 bytes .../project_native/static/description/G12.png | Bin 0 -> 9164 bytes .../project_native/static/description/G13.png | Bin 0 -> 16576 bytes .../project_native/static/description/G15.png | Bin 0 -> 17067 bytes .../project_native/static/description/G16.png | Bin 0 -> 19968 bytes .../project_native/static/description/G20.png | Bin 0 -> 6810 bytes .../project_native/static/description/G21.png | Bin 0 -> 15787 bytes .../project_native/static/description/G25.png | Bin 0 -> 4083 bytes .../project_native/static/description/G26.png | Bin 0 -> 36207 bytes .../project_native/static/description/G27.png | Bin 0 -> 35231 bytes .../project_native/static/description/G28.png | Bin 0 -> 32366 bytes .../project_native/static/description/G29.png | Bin 0 -> 29718 bytes .../static/description/Gantt_Kanban_stage.png | Bin 0 -> 103748 bytes .../description/Gantt_Odoo_Add_Task.png | Bin 0 -> 18029 bytes .../Gantt_Odoo_Attachemnt_Icon_01.png | Bin 0 -> 1363 bytes .../description/Gantt_Odoo_Backward_01.png | Bin 0 -> 78675 bytes .../description/Gantt_Odoo_Backward_02.png | Bin 0 -> 60044 bytes .../description/Gantt_Odoo_Backward_03.png | Bin 0 -> 15096 bytes .../description/Gantt_Odoo_Calendar_01.png | Bin 0 -> 51109 bytes .../description/Gantt_Odoo_Calendar_02.png | Bin 0 -> 81064 bytes .../description/Gantt_Odoo_Calendar_03.png | Bin 0 -> 59280 bytes .../description/Gantt_Odoo_Calendar_04.png | Bin 0 -> 88644 bytes .../description/Gantt_Odoo_Calendar_05.png | Bin 0 -> 57755 bytes .../description/Gantt_Odoo_Calendar_06.png | Bin 0 -> 17460 bytes .../description/Gantt_Odoo_Calendar_07.png | Bin 0 -> 36781 bytes .../description/Gantt_Odoo_Calendar_08.png | Bin 0 -> 154843 bytes .../description/Gantt_Odoo_Calendar_09.png | Bin 0 -> 120202 bytes .../Gantt_Odoo_Critical_Path_01.png | Bin 0 -> 110021 bytes .../Gantt_Odoo_Critical_Path_02.png | Bin 0 -> 36814 bytes .../Gantt_Odoo_Critical_Path_03.png | Bin 0 -> 48794 bytes .../Gantt_Odoo_Critical_Path_04.png | Bin 0 -> 30588 bytes .../Gantt_Odoo_Critical_Path_05.png | Bin 0 -> 59145 bytes .../Gantt_Odoo_Critical_Path_06.png | Bin 0 -> 33464 bytes .../Gantt_Odoo_Deadline_Control_01.png | Bin 0 -> 6045 bytes .../Gantt_Odoo_Deadline_Control_02.png | Bin 0 -> 4772 bytes .../static/description/Gantt_Odoo_Done_01.png | Bin 0 -> 1888 bytes .../static/description/Gantt_Odoo_Done_02.png | Bin 0 -> 1818 bytes .../Gantt_Odoo_Duration_Scale_01.png | Bin 0 -> 46885 bytes .../Gantt_Odoo_Duration_Scale_02.png | Bin 0 -> 24956 bytes .../Gantt_Odoo_Duration_Scale_03.png | Bin 0 -> 25610 bytes .../Gantt_Odoo_Duration_Scale_04.png | Bin 0 -> 20938 bytes .../description/Gantt_Odoo_Fold_State_01.png | Bin 0 -> 14274 bytes .../description/Gantt_Odoo_Fold_State_02.png | Bin 0 -> 18181 bytes .../description/Gantt_Odoo_ISOweek_01.png | Bin 0 -> 52510 bytes .../description/Gantt_Odoo_ISOweek_02.png | Bin 0 -> 49383 bytes .../description/Gantt_Odoo_ISOweek_03.png | Bin 0 -> 68840 bytes .../description/Gantt_Odoo_List_Item_01.png | Bin 0 -> 39278 bytes .../Gantt_Odoo_Not_allow_Group_1.png | Bin 0 -> 19440 bytes .../Gantt_Odoo_Not_allow_Group_2.png | Bin 0 -> 88698 bytes .../Gantt_Odoo_Open_Tree_Group_1.png | Bin 0 -> 28644 bytes .../Gantt_Odoo_Open_Tree_Group_2.png | Bin 0 -> 45652 bytes .../description/Gantt_Odoo_Order_by_01.png | Bin 0 -> 10444 bytes .../Gantt_Odoo_Predecessor_Link_01.png | Bin 0 -> 8219 bytes .../Gantt_Odoo_Predecessor_Link_02.png | Bin 0 -> 18188 bytes .../description/Gantt_Odoo_Project_View.png | Bin 0 -> 113345 bytes .../description/Gantt_Odoo_Resources_01.png | Bin 0 -> 72141 bytes .../description/Gantt_Odoo_Resources_02-1.png | Bin 0 -> 79205 bytes .../description/Gantt_Odoo_Resources_02-2.png | Bin 0 -> 67732 bytes .../description/Gantt_Odoo_Resources_02.png | Bin 0 -> 23717 bytes .../description/Gantt_Odoo_Resources_03-1.png | Bin 0 -> 57774 bytes .../description/Gantt_Odoo_Resources_03.png | Bin 0 -> 25433 bytes .../description/Gantt_Odoo_Resources_04.png | Bin 0 -> 9493 bytes .../description/Gantt_Odoo_Resources_05.png | Bin 0 -> 19090 bytes .../description/Gantt_Odoo_Resources_06.png | Bin 0 -> 54354 bytes .../description/Gantt_Odoo_Resources_07.png | Bin 0 -> 68277 bytes .../Gantt_Odoo_Task_Default_01.png | Bin 0 -> 59829 bytes .../Gantt_Odoo_Task_Default_02.png | Bin 0 -> 24794 bytes .../description/Gantt_Odoo_UI_control_01.png | Bin 0 -> 24628 bytes .../description/Gantt_Odoo_UI_new_01.png | Bin 0 -> 56072 bytes .../description/Gantt_Odoo_UI_rename_01.png | Bin 0 -> 13319 bytes .../description/Gantt_Odoo_UI_rename_02.png | Bin 0 -> 8534 bytes .../description/Gantt_Odoo_arrows_01.png | Bin 0 -> 22559 bytes .../description/Gantt_Odoo_arrows_02.png | Bin 0 -> 21743 bytes .../static/description/Gantt_PDF_menu.png | Bin 0 -> 59604 bytes .../description/Gantt_UI_long_name_1.png | Bin 0 -> 50324 bytes .../description/Gantt_UI_long_name_2.png | Bin 0 -> 57433 bytes .../static/description/S1_group_project.png | Bin 0 -> 64760 bytes .../static/description/S2_sorting.png | Bin 0 -> 27620 bytes .../static/description/S3_fullscreent.png | Bin 0 -> 16125 bytes .../static/description/S3_grouping.png | Bin 0 -> 22260 bytes .../static/description/arrow_all.png | Bin 0 -> 25420 bytes .../static/description/arrow_ff.png | Bin 0 -> 12162 bytes .../static/description/arrow_fs.png | Bin 0 -> 20538 bytes .../static/description/arrow_predecessor.png | Bin 0 -> 44935 bytes .../static/description/arrow_sf.png | Bin 0 -> 10778 bytes .../static/description/arrow_ss.png | Bin 0 -> 9219 bytes .../static/description/banner.gif | Bin 0 -> 255097 bytes .../static/description/ct01.png | Bin 0 -> 39508 bytes .../static/description/ct02.png | Bin 0 -> 23179 bytes .../static/description/form_view.png | Bin 0 -> 28648 bytes .../description/gantt_native_e_1_menu.png | Bin 0 -> 19183 bytes .../description/gantt_native_folding_1.png | Bin 0 -> 43646 bytes .../description/gantt_native_folding_2.png | Bin 0 -> 33534 bytes .../gantt_odoo_native_b_group_1.png | Bin 0 -> 89112 bytes .../description/gantt_odoo_native_dag_1.png | Bin 0 -> 78545 bytes .../description/gantt_odoo_native_dag_2.png | Bin 0 -> 79646 bytes .../description/gantt_odoo_native_limit_1.png | Bin 0 -> 12904 bytes .../description/gantt_odoo_native_limit_2.png | Bin 0 -> 12431 bytes .../description/gantt_odoo_native_limit_3.png | Bin 0 -> 12440 bytes .../static/description/gh_01.png | Bin 0 -> 6875 bytes .../static/description/gh_done.png | Bin 0 -> 2096 bytes .../static/description/gh_ghost.png | Bin 0 -> 3015 bytes .../static/description/icon.png | Bin 0 -> 35341 bytes .../static/description/index.html | 1699 ++++++++++++ .../static/description/list_view.png | Bin 0 -> 39564 bytes .../static/description/proj_start_date.png | Bin 0 -> 7103 bytes .../project_native/static/description/sc1.png | Bin 0 -> 8589 bytes .../project_native/static/description/sc2.png | Bin 0 -> 2542 bytes .../static/description/sm01.png | Bin 0 -> 49171 bytes .../static/description/sm02.png | Bin 0 -> 30748 bytes .../static/description/sm03.png | Bin 0 -> 27415 bytes .../static/description/sm04.png | Bin 0 -> 5861 bytes .../views/project_calendar_access_view.xml | 31 + .../views/project_project_view.xml | 18 + .../views/project_task_detail_plan_view.xml | 113 + .../views/project_task_resource_view.xml | 128 + .../views/project_task_view.xml | 320 +++ .../project_native/views/resource_views.xml | 18 + .../project_native_custom/__init__.py | 5 + .../project_native_custom/__manifest__.py | 28 + .../project_native_custom/i18n/ar_001.po | 63 + .../project_native_custom/models/__init__.py | 3 + .../models/project_task.py | 34 + .../security/security.xml | 19 + .../views/project_project_view.xml | 17 + .../views/project_task_view.xml | 64 + .../project_native_report_advance/__init__.py | 4 + .../__manifest__.py | 43 + .../doc/.vscode/settings.json | 3 + .../doc/RELEASE_NOTES.md | 11 + .../doc/index.rst | 35 + .../i18n/ar_001.po | 315 +++ .../security/ir.model.access.csv | 2 + .../security/security.xml | 19 + .../static/description/Gantt_native_pdf_1.png | Bin 0 -> 59340 bytes .../static/description/Gantt_native_pdf_2.png | Bin 0 -> 21084 bytes .../static/description/Gantt_native_pdf_3.png | Bin 0 -> 174303 bytes .../static/description/Gantt_native_pdf_4.png | Bin 0 -> 148483 bytes .../static/description/banner.gif | Bin 0 -> 93774 bytes .../static/description/icon.png | Bin 0 -> 8644 bytes .../static/description/index.html | 120 + .../wizard/__init__.py | 1 + .../wizard/project_native_pdf.py | 1392 ++++++++++ .../wizard/project_native_pdf_view.xml | 32 + .../project_risk_register/__init__.py | 3 + .../project_risk_register/__manifest__.py | 15 + .../project_risk_register/i18n/ar_001.po | 152 ++ .../project_risk_register/models/__init__.py | 3 + .../project_risk_register/models/project.py | 38 + .../security/ir.model.access.csv | 2 + .../views/project_views.xml | 36 + .../project_scrum_agile/LICENSE/LICENSE | 166 ++ odex25_project/project_scrum_agile/README.rst | 97 + .../project_scrum_agile/__init__.py | 4 + .../project_scrum_agile/__manifest__.py | 105 + .../data/project_scrum_extended_data.xml | 321 +++ .../project_scrum_agile/models/__init__.py | 9 + .../project_scrum_agile/models/hr_employee.py | 11 + .../project_scrum_agile/models/project.py | 108 + .../models/project_scrum.py | 1349 ++++++++++ .../models/project_scrum_devteam.py | 26 + .../models/project_scrum_release.py | 53 + .../models/project_scrum_role.py | 14 + .../models/project_scrum_sandbox.py | 28 + .../security/ir.model.access.csv | 62 + .../security/project_scrum_security.xml | 32 + ...t Scrum Management Agile Methodology 1.jpg | Bin 0 -> 810862 bytes .../Project-Scrum-Management-Agile-banner.png | Bin 0 -> 47618 bytes .../static/description/arrow_img-left.png | Bin 0 -> 967 bytes .../static/description/arrow_img-right.png | Bin 0 -> 956 bytes .../static/description/backlog_1.jpg | Bin 0 -> 114828 bytes .../static/description/chart_3.jpg | Bin 0 -> 209644 bytes .../static/description/chart_4.jpg | Bin 0 -> 162009 bytes .../static/description/chart_5.jpg | Bin 0 -> 191164 bytes .../static/description/customise.png | Bin 0 -> 9262 bytes .../static/description/div-bg.png | Bin 0 -> 58432 bytes .../static/description/header-logo.png | Bin 0 -> 7810 bytes .../static/description/hire.png | Bin 0 -> 10685 bytes .../static/description/icon.png | Bin 0 -> 6138 bytes .../static/description/icons/FSM.png | Bin 0 -> 15166 bytes .../static/description/icons/HRMS.png | Bin 0 -> 11720 bytes .../icons/Project-Scrum-Portal-Icon.png | Bin 0 -> 3828 bytes .../icons/Web-Auto-Reload-Refresh-icn.png | Bin 0 -> 2491 bytes .../icons/Web-Email-Interface-icn.png | Bin 0 -> 7541 bytes .../static/description/icons/azure_sso.png | Bin 0 -> 3570 bytes .../static/description/icons/biometrics.png | Bin 0 -> 12657 bytes .../static/description/icons/education.png | Bin 0 -> 10619 bytes .../static/description/icons/fleet.png | Bin 0 -> 10883 bytes .../static/description/icons/freight_mgt.png | Bin 0 -> 7430 bytes .../static/description/icons/gym.png | Bin 0 -> 10061 bytes .../static/description/icons/hotel.png | Bin 0 -> 14107 bytes .../description/icons/hr_attendance.jpeg | Bin 0 -> 3502 bytes .../static/description/icons/office365.png | Bin 0 -> 8703 bytes .../static/description/icons/popup.png | Bin 0 -> 3417 bytes .../static/description/icons/property.png | Bin 0 -> 10224 bytes .../static/description/icons/ring.png | Bin 0 -> 14872 bytes .../static/description/icons/sale_dost.png | Bin 0 -> 6765 bytes .../static/description/icons/singapore.png | Bin 0 -> 11904 bytes .../static/description/icons/spa-salon.png | Bin 0 -> 13383 bytes .../static/description/icons/user_mailbox.png | Bin 0 -> 9363 bytes .../static/description/icons/visa.png | Bin 0 -> 14674 bytes .../static/description/implementation.png | Bin 0 -> 8174 bytes .../static/description/index.html | 1046 ++++++++ .../static/description/integration.png | Bin 0 -> 9708 bytes .../static/description/meeting_6.jpg | Bin 0 -> 192168 bytes .../static/description/sprint_2.jpg | Bin 0 -> 226808 bytes .../static/description/support.png | Bin 0 -> 10496 bytes .../static/src/img/agile.png | Bin 0 -> 1416 bytes .../static/src/img/icon.png | Bin 0 -> 16349 bytes .../static/src/img/icon1.png | Bin 0 -> 6187 bytes .../static/src/img/release.png | Bin 0 -> 898 bytes .../static/src/img/tasks_icon.png | Bin 0 -> 2545 bytes .../views/account_analytic_line_view.xml | 141 + .../views/email_template.xml | 15 + .../views/hr_employee_view.xml | 18 + .../views/project_scrum_devteam_view.xml | 94 + .../views/project_scrum_release_view.xml | 156 ++ .../views/project_scrum_role_view.xml | 54 + .../views/project_scrum_sandbox_view.xml | 89 + .../views/project_scrum_view.xml | 929 +++++++ .../views/project_view.xml | 81 + .../project_scrum_agile/wizards/__init__.py | 6 + .../wizards/analytic_timesheet.py | 28 + .../wizards/analytic_timesheet_view.xml | 29 + .../project_scrum_backlog_create_task.py | 56 + ...project_scrum_backlog_create_task_view.xml | 47 + .../wizards/project_scrum_email.py | 105 + .../wizards/project_scrum_email_view.xml | 44 + .../wizards/user_story_sandbox_to_backlog.py | 53 + .../user_story_sandbox_to_backlog_view.xml | 32 + odex25_project/project_time_plan/__init__.py | 3 + .../project_time_plan/__manifest__.py | 22 + .../project_time_plan/models/__init__.py | 3 + .../project_time_plan/models/project_phase.py | 90 + .../models/project_time_plan.py | 158 ++ .../project_time_plan/models/res_company.py | 11 + .../models/res_config_setting.py | 18 + .../security/ir.model.access.csv | 5 + .../views/project_phase_views.xml | 37 + .../views/project_time_plan_view.xml | 172 ++ .../views/res_config_setting.xml | 55 + .../views/time_plan_detail.xml | 45 + .../project_time_plan/wizard/__init__.py | 2 + .../wizard/edit_project_phase.py | 25 + .../wizard/edit_project_phase_view.xml | 16 + .../wizard/week_generation_wizard.py | 83 + .../wizard/week_generation_wizard_views.xml | 37 + .../project_variation_order/__init__.py | 3 + .../project_variation_order/__manifest__.py | 20 + .../data/mail_data.xml | 31 + .../data/project_data.xml | 16 + .../project_variation_order/i18n/ar_001.po | 562 ++++ .../models/__init__.py | 3 + .../models/project_variation_order.py | 262 ++ .../security/ir.model.access.csv | 2 + .../security/project_security.xml | 36 + .../views/project_variation_order_view.xml | 247 ++ odex25_project/purchase_project/__init__.py | 4 + .../purchase_project/__manifest__.py | 22 + .../purchase_project/i18n/ar_001.po | 320 +++ .../purchase_project/models/__init__.py | 5 + .../purchase_project/models/product.py | 66 + .../purchase_project/models/project.py | 171 ++ .../purchase_project/models/purchase_order.py | 360 +++ .../security/ir.model.access.csv | 3 + .../security/sale_project_security.xml | 15 + .../purchase_project/tests/__init__.py | 5 + .../tests/test_child_tasks.py | 216 ++ .../tests/test_sale_project.py | 189 ++ .../purchase_project/views/product_views.xml | 25 + .../views/project_task_views.xml | 103 + .../views/purchase_order_views.xml | 31 + odex25_project/task_survey/__init__.py | 4 + odex25_project/task_survey/__manifest__.py | 20 + .../task_survey/controllers/__init__.py | 3 + .../task_survey/controllers/controllers.py | 21 + odex25_project/task_survey/demo/demo.xml | 30 + odex25_project/task_survey/i18n/ar_001.po | 66 + odex25_project/task_survey/models/__init__.py | 4 + odex25_project/task_survey/models/models.py | 18 + .../task_survey/models/project_task_survey.py | 41 + .../task_survey/security/ir.model.access.csv | 5 + .../task_survey/views/project_task_survey.xml | 40 + .../task_survey/views/templates.xml | 24 + odex25_project/task_survey/views/views.xml | 60 + .../to_safe_confirm_button/__init__.py | 1 + .../to_safe_confirm_button/__manifest__.py | 44 + .../static/src/js/safe_confirm.js | 50 + .../to_safe_confirm_button/views/assets.xml | 10 + odex25_project/web_gantt_native/__init__.py | 2 + .../web_gantt_native/__manifest__.py | 40 + .../web_gantt_native/doc/changelog.md | 82 + odex25_project/web_gantt_native/doc/index.md | 3 + odex25_project/web_gantt_native/doc/index.rst | 49 + .../web_gantt_native/i18n/ar_001.po | 843 ++++++ .../images/gantt_native_view.png | Bin 0 -> 436843 bytes odex25_project/web_gantt_native/ir_ui_view.py | 7 + .../web_gantt_native/models/__init__.py | 2 + .../models/gantt_native_predecessor.py | 48 + .../models/gantt_native_tool.py | 22 + .../static/description/G0.png | Bin 0 -> 436843 bytes .../static/description/banner.gif | Bin 0 -> 259028 bytes .../static/description/gantt_native_main.gif | Bin 0 -> 1857104 bytes .../static/description/icon.png | Bin 0 -> 36527 bytes .../static/description/index.html | 76 + .../static/src/css/gantt_native copy.css | 2216 +++++++++++++++ .../static/src/css/gantt_native.css | 2377 +++++++++++++++++ .../static/src/css/gantt_native_ztree.css | 440 +++ .../static/src/css/img/loading.gif | Bin 0 -> 381 bytes .../static/src/js/gantt_item_action.js | 135 + .../static/src/js/gantt_item_info.js | 181 ++ .../static/src/js/gantt_item_options.js | 352 +++ .../static/src/js/gantt_item_ztree.js | 977 +++++++ .../static/src/js/gantt_pager.js | 165 ++ .../static/src/js/gantt_timeline_arrow.js | 123 + .../src/js/gantt_timeline_arrow_draw.js | 596 +++++ .../static/src/js/gantt_timeline_bar_docs.js | 223 ++ .../static/src/js/gantt_timeline_bar_first.js | 230 ++ .../src/js/gantt_timeline_bar_summary.js | 96 + .../static/src/js/gantt_timeline_data.js | 1207 +++++++++ .../static/src/js/gantt_timeline_ghost.js | 172 ++ .../static/src/js/gantt_timeline_head.js | 175 ++ .../static/src/js/gantt_timeline_header.js | 295 ++ .../src/js/gantt_timeline_header_hint.js | 57 + .../static/src/js/gantt_timeline_info.js | 111 + .../src/js/gantt_timeline_intersection.js | 123 + .../static/src/js/gantt_timeline_res_bar.js | 272 ++ .../static/src/js/gantt_timeline_res_level.js | 186 ++ .../static/src/js/gantt_timeline_scroll.js | 177 ++ .../static/src/js/gantt_tool_field.js | 653 +++++ .../static/src/js/gantt_tool_hint.js | 105 + .../static/src/js/gantt_tool_tip.js | 240 ++ .../static/src/js/native_gantt_controller.js | 650 +++++ .../static/src/js/native_gantt_data.js | 77 + .../static/src/js/native_gantt_model.js | 762 ++++++ .../static/src/js/native_gantt_renderer.js | 578 ++++ .../static/src/js/native_gantt_view.js | 63 + .../static/src/lib/jquery.ztree.core.js | 2006 ++++++++++++++ .../static/src/lib/jquery.ztree.exedit.js | 1204 +++++++++ .../web_gantt_native/static/src/lib/twix.js | 669 +++++ .../static/src/xml/web_gantt_template.xml | 239 ++ .../web_gantt_native/views/web_gantt_src.xml | 74 + .../web_widget_colorpicker/README.rst | 41 + .../web_widget_colorpicker/__init__.py | 2 + .../web_widget_colorpicker/__manifest__.py | 50 + .../images/form_view_edit.png | Bin 0 -> 23179 bytes .../images/form_view_no_edit.png | Bin 0 -> 17516 bytes .../static/description/form_view_edit.png | Bin 0 -> 23179 bytes .../static/description/form_view_no_edit.png | Bin 0 -> 17516 bytes .../static/description/icon.png | Bin 0 -> 60077 bytes .../static/description/index.html | 80 + .../static/src/css/widget.css | 30 + .../static/src/js/widget.js | 58 + .../css/bootstrap-colorpicker.css | 230 ++ .../css/bootstrap-colorpicker.css.map | 1 + .../css/bootstrap-colorpicker.min.css | 10 + .../css/bootstrap-colorpicker.min.css.map | 1 + .../alpha-horizontal.png | Bin 0 -> 557 bytes .../img/bootstrap-colorpicker/alpha.png | Bin 0 -> 488 bytes .../bootstrap-colorpicker/hue-horizontal.png | Bin 0 -> 478 bytes .../img/bootstrap-colorpicker/hue.png | Bin 0 -> 504 bytes .../img/bootstrap-colorpicker/saturation.png | Bin 0 -> 4143 bytes .../js/bootstrap-colorpicker.js | 1325 +++++++++ .../js/bootstrap-colorpicker.min.js | 5 + .../static/src/xml/widget.xml | 24 + .../view/web_widget_colorpicker_view.xml | 17 + .../web_widget_time_delta/README.rst | 51 + .../web_widget_time_delta/__init__.py | 2 + .../web_widget_time_delta/__manifest__.py | 72 + .../web_widget_time_delta/i18n/ar_001.po | 71 + .../images/form_view.png | Bin 0 -> 28648 bytes .../images/list_view.png | Bin 0 -> 39564 bytes .../static/description/form_view.png | Bin 0 -> 28648 bytes .../static/description/icon.png | Bin 0 -> 28648 bytes .../static/description/index.html | 80 + .../static/description/list_view.png | Bin 0 -> 39564 bytes .../static/src/css/widget.css | 48 + .../static/src/js/widget.js | 171 ++ .../src/lib/duration-humanize/README.md | 280 ++ .../duration-humanize/humanize-duration.js | 736 +++++ .../static/src/lib/duration-picker/README.md | 56 + .../jquery-duration-picker.css | 19 + .../duration-picker/jquery-duration-picker.js | 164 ++ .../static/src/xml/widget.xml | 23 + .../view/web_widget_time_delta_view.xml | 16 + 538 files changed, 53148 insertions(+), 1 deletion(-) create mode 100644 odex25_project/kpi_scorecard_odex/__init__.py create mode 100644 odex25_project/kpi_scorecard_odex/__manifest__.py create mode 100644 odex25_project/kpi_scorecard_odex/i18n/ar_001.po create mode 100644 odex25_project/kpi_scorecard_odex/models/__init__.py create mode 100644 odex25_project/kpi_scorecard_odex/models/kpi_category.py create mode 100644 odex25_project/kpi_scorecard_odex/models/kpi_item.py create mode 100644 odex25_project/kpi_scorecard_odex/models/kpi_period.py create mode 100644 odex25_project/kpi_scorecard_odex/models/kpi_scorecard_line.py create mode 100644 odex25_project/kpi_scorecard_odex/models/partner_target.py create mode 100644 odex25_project/kpi_scorecard_odex/reports/__init__.py create mode 100644 odex25_project/kpi_scorecard_odex/security/ir.model.access.csv create mode 100644 odex25_project/kpi_scorecard_odex/views/kpi_category.xml create mode 100644 odex25_project/kpi_scorecard_odex/views/kpi_item.xml create mode 100644 odex25_project/kpi_scorecard_odex/views/kpi_scorecard_line.xml create mode 100644 odex25_project/kpi_scorecard_odex/views/menu_security_cus.xml create mode 100644 odex25_project/odex25_helpdesk_sale/__init__.py create mode 100644 odex25_project/odex25_helpdesk_sale/__manifest__.py create mode 100644 odex25_project/odex25_helpdesk_sale/data/odex25_helpdesk_sale_demo.xml create mode 100644 odex25_project/odex25_helpdesk_sale/i18n/ar.po create mode 100644 odex25_project/odex25_helpdesk_sale/models/__init__.py create mode 100644 odex25_project/odex25_helpdesk_sale/models/odex25_helpdesk.py create mode 100644 odex25_project/odex25_helpdesk_sale/static/description/icon.png create mode 100644 odex25_project/odex25_helpdesk_sale/views/odex25_helpdesk_views.xml create mode 100644 odex25_project/odex25_helpdesk_timesheet/__init__.py create mode 100644 odex25_project/odex25_helpdesk_timesheet/__manifest__.py create mode 100644 odex25_project/odex25_helpdesk_timesheet/data/odex25_helpdesk_timesheet_data.xml create mode 100644 odex25_project/odex25_helpdesk_timesheet/data/odex25_helpdesk_timesheet_demo.xml create mode 100644 odex25_project/odex25_helpdesk_timesheet/i18n/ar.po create mode 100644 odex25_project/odex25_helpdesk_timesheet/models/__init__.py create mode 100644 odex25_project/odex25_helpdesk_timesheet/models/analytic.py create mode 100644 odex25_project/odex25_helpdesk_timesheet/models/odex25_helpdesk.py create mode 100644 odex25_project/odex25_helpdesk_timesheet/models/project.py create mode 100644 odex25_project/odex25_helpdesk_timesheet/security/ir.model.access.csv create mode 100644 odex25_project/odex25_helpdesk_timesheet/security/odex25_helpdesk_timesheet_security.xml create mode 100644 odex25_project/odex25_helpdesk_timesheet/static/description/icon.png create mode 100644 odex25_project/odex25_helpdesk_timesheet/tests/__init__.py create mode 100644 odex25_project/odex25_helpdesk_timesheet/tests/test_project.py create mode 100644 odex25_project/odex25_helpdesk_timesheet/views/odex25_helpdesk_views.xml create mode 100644 odex25_project/odex25_helpdesk_timesheet/views/project_views.xml create mode 100644 odex25_project/odex25_helpdesk_timesheet/wizard/__init__.py create mode 100644 odex25_project/odex25_helpdesk_timesheet/wizard/odex25_helpdesk_ticket_create_timesheet.py create mode 100644 odex25_project/odex25_helpdesk_timesheet/wizard/odex25_helpdesk_ticket_create_timesheet_views.xml create mode 100644 odex25_project/project_base/.idea/inspectionProfiles/profiles_settings.xml create mode 100644 odex25_project/project_base/.idea/misc.xml create mode 100644 odex25_project/project_base/.idea/modules.xml create mode 100644 odex25_project/project_base/.idea/project_base.iml create mode 100644 odex25_project/project_base/.idea/workspace.xml create mode 100644 odex25_project/project_base/__init__.py create mode 100644 odex25_project/project_base/__manifest__.py create mode 100644 odex25_project/project_base/data/project_cron.xml create mode 100644 odex25_project/project_base/data/project_data.xml create mode 100644 odex25_project/project_base/i18n/ar.po create mode 100644 odex25_project/project_base/i18n/ar_001.po create mode 100644 odex25_project/project_base/models/__init__.py create mode 100644 odex25_project/project_base/models/project.py create mode 100644 odex25_project/project_base/models/project_invoice.py create mode 100644 odex25_project/project_base/models/project_phase.py create mode 100644 odex25_project/project_base/models/project_task.py create mode 100644 odex25_project/project_base/models/res_company.py create mode 100644 odex25_project/project_base/models/res_config_setting.py create mode 100644 odex25_project/project_base/models/sale_order.py create mode 100644 odex25_project/project_base/report/project_invoice_report_templates.xml create mode 100644 odex25_project/project_base/report/project_report_templates.xml create mode 100644 odex25_project/project_base/report/project_reports.xml create mode 100644 odex25_project/project_base/security/ir.model.access.csv create mode 100644 odex25_project/project_base/security/ir_rule_allow_users.xml create mode 100644 odex25_project/project_base/security/project_security.xml create mode 100644 odex25_project/project_base/static/src/css/progress_bar_color.css create mode 100644 odex25_project/project_base/static/src/js/progress_bar_color.js create mode 100644 odex25_project/project_base/views/asset.xml create mode 100644 odex25_project/project_base/views/project_invoice_views.xml create mode 100644 odex25_project/project_base/views/project_phase_view.xml create mode 100644 odex25_project/project_base/views/project_task_views.xml create mode 100644 odex25_project/project_base/views/project_views.xml create mode 100644 odex25_project/project_base/views/res_config_setting.xml create mode 100644 odex25_project/project_base/wizard/__init__.py create mode 100644 odex25_project/project_base/wizard/down_payment_invoice_advance.py create mode 100644 odex25_project/project_base/wizard/down_payment_invoice_advance_views.xml create mode 100644 odex25_project/project_base/wizard/edit_project_phase.py create mode 100644 odex25_project/project_base/wizard/edit_project_phase_view.xml create mode 100644 odex25_project/project_base/wizard/project_hold_reason.py create mode 100644 odex25_project/project_base/wizard/project_hold_reason_view.xml create mode 100644 odex25_project/project_budget/__init__.py create mode 100644 odex25_project/project_budget/__manifest__.py create mode 100644 odex25_project/project_budget/i18n/ar_001.po create mode 100644 odex25_project/project_budget/models/__init__.py create mode 100644 odex25_project/project_budget/models/account_budget.py create mode 100644 odex25_project/project_budget/models/project.py create mode 100644 odex25_project/project_budget/security/account_budget_security.xml create mode 100644 odex25_project/project_budget/security/ir.model.access.csv create mode 100644 odex25_project/project_budget/static/description/icon.png create mode 100644 odex25_project/project_budget/views/view.xml create mode 100644 odex25_project/project_customer_team/__init__.py create mode 100644 odex25_project/project_customer_team/__manifest__.py create mode 100644 odex25_project/project_customer_team/i18n/ar_001.po create mode 100644 odex25_project/project_customer_team/models/__init__.py create mode 100644 odex25_project/project_customer_team/models/project.py create mode 100644 odex25_project/project_customer_team/security/ir.model.access.csv create mode 100644 odex25_project/project_customer_team/views/project_views.xml create mode 100644 odex25_project/project_helpdisk_task/__init__.py create mode 100644 odex25_project/project_helpdisk_task/__manifest__.py create mode 100644 odex25_project/project_helpdisk_task/models/__init__.py create mode 100644 odex25_project/project_helpdisk_task/models/project.py create mode 100644 odex25_project/project_helpdisk_task/models/project_task.py create mode 100644 odex25_project/project_helpdisk_task/views/project_task_views.xml create mode 100644 odex25_project/project_helpdisk_task/views/project_views.xml create mode 100644 odex25_project/project_maps/__init__.py create mode 100644 odex25_project/project_maps/__manifest__.py create mode 100644 odex25_project/project_maps/i18n/ar_001.po create mode 100644 odex25_project/project_maps/models/__init__.py create mode 100644 odex25_project/project_maps/models/project_project.py create mode 100644 odex25_project/project_maps/views/project_project_view.xml create mode 100644 odex25_project/project_metrics/__init__.py create mode 100644 odex25_project/project_metrics/__manifest__.py create mode 100644 odex25_project/project_metrics/models/__init__.py create mode 100644 odex25_project/project_metrics/models/project_metrics.py create mode 100644 odex25_project/project_metrics/models/project_project.py create mode 100644 odex25_project/project_metrics/models/project_task.py create mode 100644 odex25_project/project_metrics/security/ir.model.access.csv create mode 100644 odex25_project/project_metrics/views/project_metrics_views.xml create mode 100644 odex25_project/project_metrics/views/project_project_views.xml create mode 100644 odex25_project/project_metrics/views/project_task_views.xml create mode 100644 odex25_project/project_native/__init__.py create mode 100644 odex25_project/project_native/__manifest__.py create mode 100644 odex25_project/project_native/doc/RELEASE_NOTES.md create mode 100644 odex25_project/project_native/doc/index.rst create mode 100644 odex25_project/project_native/i18n/ar_001.po create mode 100644 odex25_project/project_native/images/gantt_native_view.png create mode 100644 odex25_project/project_native/models/__init__.py create mode 100644 odex25_project/project_native/models/project_task.py create mode 100644 odex25_project/project_native/models/project_task_calendar.py create mode 100644 odex25_project/project_native/models/project_task_critical_path.py create mode 100644 odex25_project/project_native/models/project_task_detail_plan.py create mode 100644 odex25_project/project_native/models/project_task_info.py create mode 100644 odex25_project/project_native/models/project_task_resource.py create mode 100644 odex25_project/project_native/models/project_task_scheduler.py create mode 100644 odex25_project/project_native/models/project_task_scheduler_calendar.py create mode 100644 odex25_project/project_native/models/project_task_tree.py create mode 100644 odex25_project/project_native/models/project_task_tree_update.py create mode 100644 odex25_project/project_native/models/resource.py create mode 100644 odex25_project/project_native/security/ir.model.access.csv create mode 100644 odex25_project/project_native/static/description/A1.png create mode 100644 odex25_project/project_native/static/description/A2.png create mode 100644 odex25_project/project_native/static/description/A3.png create mode 100644 odex25_project/project_native/static/description/G01.png create mode 100644 odex25_project/project_native/static/description/G02.png create mode 100644 odex25_project/project_native/static/description/G03.png create mode 100644 odex25_project/project_native/static/description/G04.png create mode 100644 odex25_project/project_native/static/description/G05.png create mode 100644 odex25_project/project_native/static/description/G06.png create mode 100644 odex25_project/project_native/static/description/G07.png create mode 100644 odex25_project/project_native/static/description/G09.png create mode 100644 odex25_project/project_native/static/description/G10.png create mode 100644 odex25_project/project_native/static/description/G12.png create mode 100644 odex25_project/project_native/static/description/G13.png create mode 100644 odex25_project/project_native/static/description/G15.png create mode 100644 odex25_project/project_native/static/description/G16.png create mode 100644 odex25_project/project_native/static/description/G20.png create mode 100644 odex25_project/project_native/static/description/G21.png create mode 100644 odex25_project/project_native/static/description/G25.png create mode 100644 odex25_project/project_native/static/description/G26.png create mode 100644 odex25_project/project_native/static/description/G27.png create mode 100644 odex25_project/project_native/static/description/G28.png create mode 100644 odex25_project/project_native/static/description/G29.png create mode 100644 odex25_project/project_native/static/description/Gantt_Kanban_stage.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Add_Task.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Attachemnt_Icon_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Backward_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Backward_02.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Backward_03.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Calendar_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Calendar_02.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Calendar_03.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Calendar_04.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Calendar_05.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Calendar_06.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Calendar_07.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Calendar_08.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Calendar_09.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Critical_Path_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Critical_Path_02.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Critical_Path_03.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Critical_Path_04.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Critical_Path_05.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Critical_Path_06.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Deadline_Control_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Deadline_Control_02.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Done_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Done_02.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Duration_Scale_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Duration_Scale_02.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Duration_Scale_03.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Duration_Scale_04.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Fold_State_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Fold_State_02.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_ISOweek_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_ISOweek_02.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_ISOweek_03.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_List_Item_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Not_allow_Group_1.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Not_allow_Group_2.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Open_Tree_Group_1.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Open_Tree_Group_2.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Order_by_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Predecessor_Link_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Predecessor_Link_02.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Project_View.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Resources_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Resources_02-1.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Resources_02-2.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Resources_02.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Resources_03-1.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Resources_03.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Resources_04.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Resources_05.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Resources_06.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Resources_07.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Task_Default_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_Task_Default_02.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_UI_control_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_UI_new_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_UI_rename_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_UI_rename_02.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_arrows_01.png create mode 100644 odex25_project/project_native/static/description/Gantt_Odoo_arrows_02.png create mode 100644 odex25_project/project_native/static/description/Gantt_PDF_menu.png create mode 100644 odex25_project/project_native/static/description/Gantt_UI_long_name_1.png create mode 100644 odex25_project/project_native/static/description/Gantt_UI_long_name_2.png create mode 100644 odex25_project/project_native/static/description/S1_group_project.png create mode 100644 odex25_project/project_native/static/description/S2_sorting.png create mode 100644 odex25_project/project_native/static/description/S3_fullscreent.png create mode 100644 odex25_project/project_native/static/description/S3_grouping.png create mode 100644 odex25_project/project_native/static/description/arrow_all.png create mode 100644 odex25_project/project_native/static/description/arrow_ff.png create mode 100644 odex25_project/project_native/static/description/arrow_fs.png create mode 100644 odex25_project/project_native/static/description/arrow_predecessor.png create mode 100644 odex25_project/project_native/static/description/arrow_sf.png create mode 100644 odex25_project/project_native/static/description/arrow_ss.png create mode 100644 odex25_project/project_native/static/description/banner.gif create mode 100644 odex25_project/project_native/static/description/ct01.png create mode 100644 odex25_project/project_native/static/description/ct02.png create mode 100644 odex25_project/project_native/static/description/form_view.png create mode 100644 odex25_project/project_native/static/description/gantt_native_e_1_menu.png create mode 100644 odex25_project/project_native/static/description/gantt_native_folding_1.png create mode 100644 odex25_project/project_native/static/description/gantt_native_folding_2.png create mode 100644 odex25_project/project_native/static/description/gantt_odoo_native_b_group_1.png create mode 100644 odex25_project/project_native/static/description/gantt_odoo_native_dag_1.png create mode 100644 odex25_project/project_native/static/description/gantt_odoo_native_dag_2.png create mode 100644 odex25_project/project_native/static/description/gantt_odoo_native_limit_1.png create mode 100644 odex25_project/project_native/static/description/gantt_odoo_native_limit_2.png create mode 100644 odex25_project/project_native/static/description/gantt_odoo_native_limit_3.png create mode 100644 odex25_project/project_native/static/description/gh_01.png create mode 100644 odex25_project/project_native/static/description/gh_done.png create mode 100644 odex25_project/project_native/static/description/gh_ghost.png create mode 100644 odex25_project/project_native/static/description/icon.png create mode 100644 odex25_project/project_native/static/description/index.html create mode 100644 odex25_project/project_native/static/description/list_view.png create mode 100644 odex25_project/project_native/static/description/proj_start_date.png create mode 100644 odex25_project/project_native/static/description/sc1.png create mode 100644 odex25_project/project_native/static/description/sc2.png create mode 100644 odex25_project/project_native/static/description/sm01.png create mode 100644 odex25_project/project_native/static/description/sm02.png create mode 100644 odex25_project/project_native/static/description/sm03.png create mode 100644 odex25_project/project_native/static/description/sm04.png create mode 100644 odex25_project/project_native/views/project_calendar_access_view.xml create mode 100644 odex25_project/project_native/views/project_project_view.xml create mode 100644 odex25_project/project_native/views/project_task_detail_plan_view.xml create mode 100644 odex25_project/project_native/views/project_task_resource_view.xml create mode 100644 odex25_project/project_native/views/project_task_view.xml create mode 100644 odex25_project/project_native/views/resource_views.xml create mode 100644 odex25_project/project_native_custom/__init__.py create mode 100644 odex25_project/project_native_custom/__manifest__.py create mode 100644 odex25_project/project_native_custom/i18n/ar_001.po create mode 100644 odex25_project/project_native_custom/models/__init__.py create mode 100644 odex25_project/project_native_custom/models/project_task.py create mode 100644 odex25_project/project_native_custom/security/security.xml create mode 100644 odex25_project/project_native_custom/views/project_project_view.xml create mode 100644 odex25_project/project_native_custom/views/project_task_view.xml create mode 100644 odex25_project/project_native_report_advance/__init__.py create mode 100644 odex25_project/project_native_report_advance/__manifest__.py create mode 100644 odex25_project/project_native_report_advance/doc/.vscode/settings.json create mode 100644 odex25_project/project_native_report_advance/doc/RELEASE_NOTES.md create mode 100644 odex25_project/project_native_report_advance/doc/index.rst create mode 100644 odex25_project/project_native_report_advance/i18n/ar_001.po create mode 100644 odex25_project/project_native_report_advance/security/ir.model.access.csv create mode 100644 odex25_project/project_native_report_advance/security/security.xml create mode 100644 odex25_project/project_native_report_advance/static/description/Gantt_native_pdf_1.png create mode 100644 odex25_project/project_native_report_advance/static/description/Gantt_native_pdf_2.png create mode 100644 odex25_project/project_native_report_advance/static/description/Gantt_native_pdf_3.png create mode 100644 odex25_project/project_native_report_advance/static/description/Gantt_native_pdf_4.png create mode 100644 odex25_project/project_native_report_advance/static/description/banner.gif create mode 100644 odex25_project/project_native_report_advance/static/description/icon.png create mode 100644 odex25_project/project_native_report_advance/static/description/index.html create mode 100644 odex25_project/project_native_report_advance/wizard/__init__.py create mode 100644 odex25_project/project_native_report_advance/wizard/project_native_pdf.py create mode 100644 odex25_project/project_native_report_advance/wizard/project_native_pdf_view.xml create mode 100644 odex25_project/project_risk_register/__init__.py create mode 100644 odex25_project/project_risk_register/__manifest__.py create mode 100644 odex25_project/project_risk_register/i18n/ar_001.po create mode 100644 odex25_project/project_risk_register/models/__init__.py create mode 100644 odex25_project/project_risk_register/models/project.py create mode 100644 odex25_project/project_risk_register/security/ir.model.access.csv create mode 100644 odex25_project/project_risk_register/views/project_views.xml create mode 100644 odex25_project/project_scrum_agile/LICENSE/LICENSE create mode 100644 odex25_project/project_scrum_agile/README.rst create mode 100644 odex25_project/project_scrum_agile/__init__.py create mode 100644 odex25_project/project_scrum_agile/__manifest__.py create mode 100644 odex25_project/project_scrum_agile/data/project_scrum_extended_data.xml create mode 100644 odex25_project/project_scrum_agile/models/__init__.py create mode 100644 odex25_project/project_scrum_agile/models/hr_employee.py create mode 100644 odex25_project/project_scrum_agile/models/project.py create mode 100644 odex25_project/project_scrum_agile/models/project_scrum.py create mode 100644 odex25_project/project_scrum_agile/models/project_scrum_devteam.py create mode 100644 odex25_project/project_scrum_agile/models/project_scrum_release.py create mode 100644 odex25_project/project_scrum_agile/models/project_scrum_role.py create mode 100644 odex25_project/project_scrum_agile/models/project_scrum_sandbox.py create mode 100644 odex25_project/project_scrum_agile/security/ir.model.access.csv create mode 100644 odex25_project/project_scrum_agile/security/project_scrum_security.xml create mode 100644 odex25_project/project_scrum_agile/static/description/Project Scrum Management Agile Methodology 1.jpg create mode 100644 odex25_project/project_scrum_agile/static/description/Project-Scrum-Management-Agile-banner.png create mode 100644 odex25_project/project_scrum_agile/static/description/arrow_img-left.png create mode 100644 odex25_project/project_scrum_agile/static/description/arrow_img-right.png create mode 100644 odex25_project/project_scrum_agile/static/description/backlog_1.jpg create mode 100644 odex25_project/project_scrum_agile/static/description/chart_3.jpg create mode 100644 odex25_project/project_scrum_agile/static/description/chart_4.jpg create mode 100644 odex25_project/project_scrum_agile/static/description/chart_5.jpg create mode 100644 odex25_project/project_scrum_agile/static/description/customise.png create mode 100644 odex25_project/project_scrum_agile/static/description/div-bg.png create mode 100644 odex25_project/project_scrum_agile/static/description/header-logo.png create mode 100644 odex25_project/project_scrum_agile/static/description/hire.png create mode 100644 odex25_project/project_scrum_agile/static/description/icon.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/FSM.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/HRMS.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/Project-Scrum-Portal-Icon.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/Web-Auto-Reload-Refresh-icn.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/Web-Email-Interface-icn.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/azure_sso.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/biometrics.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/education.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/fleet.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/freight_mgt.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/gym.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/hotel.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/hr_attendance.jpeg create mode 100644 odex25_project/project_scrum_agile/static/description/icons/office365.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/popup.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/property.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/ring.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/sale_dost.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/singapore.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/spa-salon.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/user_mailbox.png create mode 100644 odex25_project/project_scrum_agile/static/description/icons/visa.png create mode 100644 odex25_project/project_scrum_agile/static/description/implementation.png create mode 100644 odex25_project/project_scrum_agile/static/description/index.html create mode 100644 odex25_project/project_scrum_agile/static/description/integration.png create mode 100644 odex25_project/project_scrum_agile/static/description/meeting_6.jpg create mode 100644 odex25_project/project_scrum_agile/static/description/sprint_2.jpg create mode 100644 odex25_project/project_scrum_agile/static/description/support.png create mode 100644 odex25_project/project_scrum_agile/static/src/img/agile.png create mode 100644 odex25_project/project_scrum_agile/static/src/img/icon.png create mode 100644 odex25_project/project_scrum_agile/static/src/img/icon1.png create mode 100644 odex25_project/project_scrum_agile/static/src/img/release.png create mode 100644 odex25_project/project_scrum_agile/static/src/img/tasks_icon.png create mode 100644 odex25_project/project_scrum_agile/views/account_analytic_line_view.xml create mode 100644 odex25_project/project_scrum_agile/views/email_template.xml create mode 100644 odex25_project/project_scrum_agile/views/hr_employee_view.xml create mode 100644 odex25_project/project_scrum_agile/views/project_scrum_devteam_view.xml create mode 100644 odex25_project/project_scrum_agile/views/project_scrum_release_view.xml create mode 100644 odex25_project/project_scrum_agile/views/project_scrum_role_view.xml create mode 100644 odex25_project/project_scrum_agile/views/project_scrum_sandbox_view.xml create mode 100644 odex25_project/project_scrum_agile/views/project_scrum_view.xml create mode 100644 odex25_project/project_scrum_agile/views/project_view.xml create mode 100644 odex25_project/project_scrum_agile/wizards/__init__.py create mode 100644 odex25_project/project_scrum_agile/wizards/analytic_timesheet.py create mode 100644 odex25_project/project_scrum_agile/wizards/analytic_timesheet_view.xml create mode 100644 odex25_project/project_scrum_agile/wizards/project_scrum_backlog_create_task.py create mode 100644 odex25_project/project_scrum_agile/wizards/project_scrum_backlog_create_task_view.xml create mode 100644 odex25_project/project_scrum_agile/wizards/project_scrum_email.py create mode 100644 odex25_project/project_scrum_agile/wizards/project_scrum_email_view.xml create mode 100644 odex25_project/project_scrum_agile/wizards/user_story_sandbox_to_backlog.py create mode 100644 odex25_project/project_scrum_agile/wizards/user_story_sandbox_to_backlog_view.xml create mode 100644 odex25_project/project_time_plan/__init__.py create mode 100644 odex25_project/project_time_plan/__manifest__.py create mode 100644 odex25_project/project_time_plan/models/__init__.py create mode 100644 odex25_project/project_time_plan/models/project_phase.py create mode 100644 odex25_project/project_time_plan/models/project_time_plan.py create mode 100644 odex25_project/project_time_plan/models/res_company.py create mode 100644 odex25_project/project_time_plan/models/res_config_setting.py create mode 100644 odex25_project/project_time_plan/security/ir.model.access.csv create mode 100644 odex25_project/project_time_plan/views/project_phase_views.xml create mode 100644 odex25_project/project_time_plan/views/project_time_plan_view.xml create mode 100644 odex25_project/project_time_plan/views/res_config_setting.xml create mode 100644 odex25_project/project_time_plan/views/time_plan_detail.xml create mode 100644 odex25_project/project_time_plan/wizard/__init__.py create mode 100644 odex25_project/project_time_plan/wizard/edit_project_phase.py create mode 100644 odex25_project/project_time_plan/wizard/edit_project_phase_view.xml create mode 100644 odex25_project/project_time_plan/wizard/week_generation_wizard.py create mode 100644 odex25_project/project_time_plan/wizard/week_generation_wizard_views.xml create mode 100644 odex25_project/project_variation_order/__init__.py create mode 100644 odex25_project/project_variation_order/__manifest__.py create mode 100644 odex25_project/project_variation_order/data/mail_data.xml create mode 100644 odex25_project/project_variation_order/data/project_data.xml create mode 100644 odex25_project/project_variation_order/i18n/ar_001.po create mode 100644 odex25_project/project_variation_order/models/__init__.py create mode 100644 odex25_project/project_variation_order/models/project_variation_order.py create mode 100644 odex25_project/project_variation_order/security/ir.model.access.csv create mode 100644 odex25_project/project_variation_order/security/project_security.xml create mode 100644 odex25_project/project_variation_order/views/project_variation_order_view.xml create mode 100644 odex25_project/purchase_project/__init__.py create mode 100644 odex25_project/purchase_project/__manifest__.py create mode 100644 odex25_project/purchase_project/i18n/ar_001.po create mode 100644 odex25_project/purchase_project/models/__init__.py create mode 100644 odex25_project/purchase_project/models/product.py create mode 100644 odex25_project/purchase_project/models/project.py create mode 100644 odex25_project/purchase_project/models/purchase_order.py create mode 100644 odex25_project/purchase_project/security/ir.model.access.csv create mode 100644 odex25_project/purchase_project/security/sale_project_security.xml create mode 100644 odex25_project/purchase_project/tests/__init__.py create mode 100644 odex25_project/purchase_project/tests/test_child_tasks.py create mode 100644 odex25_project/purchase_project/tests/test_sale_project.py create mode 100644 odex25_project/purchase_project/views/product_views.xml create mode 100644 odex25_project/purchase_project/views/project_task_views.xml create mode 100644 odex25_project/purchase_project/views/purchase_order_views.xml create mode 100644 odex25_project/task_survey/__init__.py create mode 100644 odex25_project/task_survey/__manifest__.py create mode 100644 odex25_project/task_survey/controllers/__init__.py create mode 100644 odex25_project/task_survey/controllers/controllers.py create mode 100644 odex25_project/task_survey/demo/demo.xml create mode 100644 odex25_project/task_survey/i18n/ar_001.po create mode 100644 odex25_project/task_survey/models/__init__.py create mode 100644 odex25_project/task_survey/models/models.py create mode 100644 odex25_project/task_survey/models/project_task_survey.py create mode 100644 odex25_project/task_survey/security/ir.model.access.csv create mode 100644 odex25_project/task_survey/views/project_task_survey.xml create mode 100644 odex25_project/task_survey/views/templates.xml create mode 100644 odex25_project/task_survey/views/views.xml create mode 100644 odex25_project/to_safe_confirm_button/__init__.py create mode 100644 odex25_project/to_safe_confirm_button/__manifest__.py create mode 100644 odex25_project/to_safe_confirm_button/static/src/js/safe_confirm.js create mode 100644 odex25_project/to_safe_confirm_button/views/assets.xml create mode 100644 odex25_project/web_gantt_native/__init__.py create mode 100644 odex25_project/web_gantt_native/__manifest__.py create mode 100644 odex25_project/web_gantt_native/doc/changelog.md create mode 100644 odex25_project/web_gantt_native/doc/index.md create mode 100644 odex25_project/web_gantt_native/doc/index.rst create mode 100644 odex25_project/web_gantt_native/i18n/ar_001.po create mode 100644 odex25_project/web_gantt_native/images/gantt_native_view.png create mode 100644 odex25_project/web_gantt_native/ir_ui_view.py create mode 100644 odex25_project/web_gantt_native/models/__init__.py create mode 100644 odex25_project/web_gantt_native/models/gantt_native_predecessor.py create mode 100644 odex25_project/web_gantt_native/models/gantt_native_tool.py create mode 100644 odex25_project/web_gantt_native/static/description/G0.png create mode 100644 odex25_project/web_gantt_native/static/description/banner.gif create mode 100644 odex25_project/web_gantt_native/static/description/gantt_native_main.gif create mode 100644 odex25_project/web_gantt_native/static/description/icon.png create mode 100644 odex25_project/web_gantt_native/static/description/index.html create mode 100644 odex25_project/web_gantt_native/static/src/css/gantt_native copy.css create mode 100644 odex25_project/web_gantt_native/static/src/css/gantt_native.css create mode 100644 odex25_project/web_gantt_native/static/src/css/gantt_native_ztree.css create mode 100644 odex25_project/web_gantt_native/static/src/css/img/loading.gif create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_item_action.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_item_info.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_item_options.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_item_ztree.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_pager.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_timeline_arrow.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_timeline_arrow_draw.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_timeline_bar_docs.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_timeline_bar_first.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_timeline_bar_summary.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_timeline_data.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_timeline_ghost.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_timeline_head.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_timeline_header.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_timeline_header_hint.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_timeline_info.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_timeline_intersection.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_timeline_res_bar.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_timeline_res_level.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_timeline_scroll.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_tool_field.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_tool_hint.js create mode 100644 odex25_project/web_gantt_native/static/src/js/gantt_tool_tip.js create mode 100644 odex25_project/web_gantt_native/static/src/js/native_gantt_controller.js create mode 100644 odex25_project/web_gantt_native/static/src/js/native_gantt_data.js create mode 100644 odex25_project/web_gantt_native/static/src/js/native_gantt_model.js create mode 100644 odex25_project/web_gantt_native/static/src/js/native_gantt_renderer.js create mode 100644 odex25_project/web_gantt_native/static/src/js/native_gantt_view.js create mode 100644 odex25_project/web_gantt_native/static/src/lib/jquery.ztree.core.js create mode 100644 odex25_project/web_gantt_native/static/src/lib/jquery.ztree.exedit.js create mode 100644 odex25_project/web_gantt_native/static/src/lib/twix.js create mode 100644 odex25_project/web_gantt_native/static/src/xml/web_gantt_template.xml create mode 100644 odex25_project/web_gantt_native/views/web_gantt_src.xml create mode 100644 odex25_project/web_widget_colorpicker/README.rst create mode 100644 odex25_project/web_widget_colorpicker/__init__.py create mode 100644 odex25_project/web_widget_colorpicker/__manifest__.py create mode 100644 odex25_project/web_widget_colorpicker/images/form_view_edit.png create mode 100644 odex25_project/web_widget_colorpicker/images/form_view_no_edit.png create mode 100644 odex25_project/web_widget_colorpicker/static/description/form_view_edit.png create mode 100644 odex25_project/web_widget_colorpicker/static/description/form_view_no_edit.png create mode 100644 odex25_project/web_widget_colorpicker/static/description/icon.png create mode 100644 odex25_project/web_widget_colorpicker/static/description/index.html create mode 100644 odex25_project/web_widget_colorpicker/static/src/css/widget.css create mode 100644 odex25_project/web_widget_colorpicker/static/src/js/widget.js create mode 100644 odex25_project/web_widget_colorpicker/static/src/lib/bootstrap-colorpicker/css/bootstrap-colorpicker.css create mode 100644 odex25_project/web_widget_colorpicker/static/src/lib/bootstrap-colorpicker/css/bootstrap-colorpicker.css.map create mode 100644 odex25_project/web_widget_colorpicker/static/src/lib/bootstrap-colorpicker/css/bootstrap-colorpicker.min.css create mode 100644 odex25_project/web_widget_colorpicker/static/src/lib/bootstrap-colorpicker/css/bootstrap-colorpicker.min.css.map create mode 100644 odex25_project/web_widget_colorpicker/static/src/lib/bootstrap-colorpicker/img/bootstrap-colorpicker/alpha-horizontal.png create mode 100644 odex25_project/web_widget_colorpicker/static/src/lib/bootstrap-colorpicker/img/bootstrap-colorpicker/alpha.png create mode 100644 odex25_project/web_widget_colorpicker/static/src/lib/bootstrap-colorpicker/img/bootstrap-colorpicker/hue-horizontal.png create mode 100644 odex25_project/web_widget_colorpicker/static/src/lib/bootstrap-colorpicker/img/bootstrap-colorpicker/hue.png create mode 100644 odex25_project/web_widget_colorpicker/static/src/lib/bootstrap-colorpicker/img/bootstrap-colorpicker/saturation.png create mode 100644 odex25_project/web_widget_colorpicker/static/src/lib/bootstrap-colorpicker/js/bootstrap-colorpicker.js create mode 100644 odex25_project/web_widget_colorpicker/static/src/lib/bootstrap-colorpicker/js/bootstrap-colorpicker.min.js create mode 100644 odex25_project/web_widget_colorpicker/static/src/xml/widget.xml create mode 100644 odex25_project/web_widget_colorpicker/view/web_widget_colorpicker_view.xml create mode 100644 odex25_project/web_widget_time_delta/README.rst create mode 100644 odex25_project/web_widget_time_delta/__init__.py create mode 100644 odex25_project/web_widget_time_delta/__manifest__.py create mode 100644 odex25_project/web_widget_time_delta/i18n/ar_001.po create mode 100644 odex25_project/web_widget_time_delta/images/form_view.png create mode 100644 odex25_project/web_widget_time_delta/images/list_view.png create mode 100644 odex25_project/web_widget_time_delta/static/description/form_view.png create mode 100644 odex25_project/web_widget_time_delta/static/description/icon.png create mode 100644 odex25_project/web_widget_time_delta/static/description/index.html create mode 100644 odex25_project/web_widget_time_delta/static/description/list_view.png create mode 100644 odex25_project/web_widget_time_delta/static/src/css/widget.css create mode 100644 odex25_project/web_widget_time_delta/static/src/js/widget.js create mode 100644 odex25_project/web_widget_time_delta/static/src/lib/duration-humanize/README.md create mode 100644 odex25_project/web_widget_time_delta/static/src/lib/duration-humanize/humanize-duration.js create mode 100644 odex25_project/web_widget_time_delta/static/src/lib/duration-picker/README.md create mode 100644 odex25_project/web_widget_time_delta/static/src/lib/duration-picker/jquery-duration-picker.css create mode 100644 odex25_project/web_widget_time_delta/static/src/lib/duration-picker/jquery-duration-picker.js create mode 100644 odex25_project/web_widget_time_delta/static/src/xml/widget.xml create mode 100644 odex25_project/web_widget_time_delta/view/web_widget_time_delta_view.xml diff --git a/README.md b/README.md index 8b10e6960..6864725ce 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ -# odex25-standard-moduless +# odex25-standard-modules This Repo contains general standard modules for all projects. diff --git a/odex25_project/kpi_scorecard_odex/__init__.py b/odex25_project/kpi_scorecard_odex/__init__.py new file mode 100644 index 000000000..30a7de2e7 --- /dev/null +++ b/odex25_project/kpi_scorecard_odex/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- + +from . import models +from . import reports + + diff --git a/odex25_project/kpi_scorecard_odex/__manifest__.py b/odex25_project/kpi_scorecard_odex/__manifest__.py new file mode 100644 index 000000000..a200accce --- /dev/null +++ b/odex25_project/kpi_scorecard_odex/__manifest__.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# (Odex - Extending the base module). +# Copyright (C) 2024 Expert Co. Ltd. (). +# +############################################################################## +{ + "name": "Odex -KPI", + "version": "1.0", + "author": "Expert Co. Ltd.", + "category": "Odex25-base/Odex-Base25", + "website": "http://www.exp-sa.com", + "installable": True, + "depends": [ + "kpi_scorecard", + + ], + "data": [ + "security/ir.model.access.csv", + "views/kpi_category.xml", + "views/kpi_item.xml", + "views/kpi_scorecard_line.xml", + 'views/menu_security_cus.xml' + + + + + + + ], + + + +} diff --git a/odex25_project/kpi_scorecard_odex/i18n/ar_001.po b/odex25_project/kpi_scorecard_odex/i18n/ar_001.po new file mode 100644 index 000000000..7f9f1e52e --- /dev/null +++ b/odex25_project/kpi_scorecard_odex/i18n/ar_001.po @@ -0,0 +1,1999 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * kpi_scorecard +# * kpi_scorecard_odex +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-03-03 00:57+0000\n" +"PO-Revision-Date: 2024-03-03 00:57+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: kpi_scorecard +#: model:ir.model.fields,help:kpi_scorecard.field_kpi_measure__date_field_ids +msgid "" +"\n" +" According to those dates Odoo will calculate whether a record is within a specified period.\n" +" In case there are a few of date fields, all of related dates should be within a period. \n" +" " +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_help.py:0 +#, python-format +msgid "" +"\n" +"
\n" +"

KPI categories serve to structure KPIs and KPI targets for comfortable navigation. Each\n" +"KPI should be assigned for a single category, what allows users to find required targets quickly just by checking the\n" +"boxes on the scorecard interface.

\n" +"

Hierarchy of categories let users also combine targets in sections to control KPIs\n" +"related to specific areas. For example, to check targets only in sales (e.g. category 'sales') or targets of a \n" +"specific sales team (e.g. category 'sales > sales team Europe').

\n" +"

Moreover, KPI categories let you administrate user accesses in a batch. Thus, you may\n" +"grant users and/or user groups an access for this category KPI ('Read Rights') or a right to update those\n" +"targets ('Edit rights)'. Thus, there would be no need to manage each KPI separately. Take into account that those\n" +"settings are additive and are not restrictive, meaning that KPI managers would any way have full rights for all\n" +"KPIs.

\n" +"
\n" +" " +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_help.py:0 +#, python-format +msgid "" +"\n" +"
\n" +"

\n" +"A KPI constant is a variable type used for formula construction. In comparison to measurements, KPI constants are fixed\n" +"and they do not depend on actual Odoo data. This allows to introduce figures which can not be retrieved from modules\n" +"and/or which should remain the same during the whole period.

\n" +"

For example, you might set the 'total size of investments' to calculate return on \n" +"investments, or the 'number of salesmen' to get sales revenue per person.

\n" +"

KPI constant value might be defined for each individual period. If the value does not \n" +"exist for a calculated period, the app would try to check the parent time frame. For instance, if this constant value\n" +"does is not set up January 2021, the app would take all the intervals which include January (e.g. Quarter 1 2021 and the\n" +"year 2021 consequentially). In case the values is not defined for those periods as well, then, the global value would be \n" +"applied.

\n" +"
\n" +" " +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_help.py:0 +#, python-format +msgid "" +"\n" +"
\n" +"

A KPI measurement is a final variable used for KPI(s) calculations. It represents\n" +"specification of basic measurement. For example, 'number of quotations of the sales team Europe' might be a precision of\n" +"a basic measurement 'total number of sales orders'.

\n" +"

Such approach significantly simplifies variables' preparation, since each basic\n" +"measurement might have an unlimited number of linked KPI measurements. So, the only thing you would need to do is to\n" +"apply extra filters (in the example 'Sales Team Name is Europe').

\n" +"

Take into account that basic measurements of the type 'Execute Python code' can't be\n" +"any more specified, since they do not relate to any records. In such a case, there is no sense to have a few KPI\n" +"measurements.

\n" +"

In a multi company environment KPI Measurements are applied globally or for each company\n" +"individually. In the former case that variable is available for any company KPI formulas, while in the latter – only for\n" +" specific one (it let make quicker overview while constructing formulas).

\n" +"
\n" +" " +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_help.py:0 +#, python-format +msgid "" +"\n" +"
\n" +"

A KPI period is a time frame for which companies set their targets to control \n" +"performance (in a similar way as financial performance is controlled within accounting/fiscal periods).

\n" +"

KPI scorecards in comparison to simple dashboard assume that you might not only have \n" +"overview of actual figures, but to compare those to real targets. However, goals should be time-constrained ('Sell as \n" +"much as possible' is not a goal, while 'Generate 100,000 Euro Revenue in the year 2021' is a good target for a sales \n" +"person, for example). That is why KPI periods are introduced.

\n" +"

The app allows to set periods of any length including intervals which cross each other \n" +"(and even the Past periods!).\n" +"To open a new KPI period you should just set start and end dates. Those dates will be used to calculate KPI actual value.\n" +"For example, KPI formula might include a basic KPI measurement for total amount of sale orders, while date field of \n" +"this measurement is defined as 'Order date'. Then, only sale orders which order date is within the period would be \n" +"taken into account. Thus, KPI scorecard would show total revenue for a given period.

\n" +"

It is recommended to have more or less strict logic of periods for comparability \n" +"purposes. Usually, KPI targets are set for a whole year and quarterly/monthly intervals. It let not only have KPI \n" +"overview, but also check historical trends. The app automatically considers various periods in order to define which \n" +"might be compared to this one, and will show users a chart of actual values by a specific KPI. It is possible to define \n" +"tolerance on the configuration page. For example, 2-days tolerance is needed to compare quarterly periods (since quarter\n" +" might take from 90 to 92 days), and 3-days tolerance for months (unluckily, February may last 28 days).

\n" +"

When end date is already in the Past, it is preferable to close the period to avoid \n" +"further updates of KPI targets actual values due to further corrections (it is not a good idea to update December KPIs \n" +"in the next August even though a sale total needs to be corrected, for example). This action is pretty much the same \n" +"as when accountant finishes a fiscal year. To close a period use the button 'Close period' (this action might be rolled\n" +"back by re-opening the period).

\n" +"

KPI periods let you also copy targets from existing periods (so, use them as a \n" +"template). To that end just push the button 'Substitute targets' and select a period with proper KPI targets. \n" +"It significantly saves time, since KPI targets usually remain similar for periods of the same length. Do not worry, \n" +"after that action you would be still able to change actual scorecard for this period (for sure, until a period is \n" +"closed).

\n" +"

Based on KPI periods you may also configure KPI formulas to rely upon period length in \n" +"days to calculate figures per days, weeks, etc. To that end use the special Measurements 'Periods Days' or 'Days Passed'\n" +"(how many days already passed in comparison to today) when you construct a formula. For example, you might have average \n" +"sales amount per week within the given period, and compare how much it changes from the previous one. That length is\n" +"calculated automatically, while you just put that to a proper formula place.

\n" +"
\n" +" " +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_help.py:0 +#, python-format +msgid "" +"\n" +"
\n" +"

A basic measurement is the core object used for retrieving actual KPI value from Odoo \n" +"data. Although basic measurements are not used themselves for formula constructions, they are required to prepare any \n" +"sort of formula variables (KPI measurements).

\n" +"

A basic measurement represents the most general calculation, while KPI measurements \n" +"specify those. For example, 'total number of sales orders' should be a basic measurement, while narrower 'number of \n" +"quotations of the sales team Europe' is recommended to be a precision of that basic measurement (so, KPI measurement).\n" +"Each basic measurement might have an unlimited number of linked KPI measurements.

\n" +"

Calculation Types

\n" +"

Basic measurements assume a few types of low-level calculations:

\n" +"
    \n" +"
  • Counting records, e.g. number of registered leads or a number of posted customer invoices. Such measurements should\n" +"have the KPI type 'Count of records'.
  • \n" +"
  • Summing up certain number field of records, e.g. sum of all orders amount total or sum of paid taxes by invoices.\n" +"Such measurements should have the KPI type 'Sum of records field'.
  • \n" +"
  • Getting of average for records' number fields, e.g. average planned hours per task or average days to assign a lead.\n" +"Such measurements should have the KPI type 'Average of records field'.
  • \n" +"
  • Executing Python code. This type requires technical knowledge, but let you compute any sort of figures based on any\n" +"Odoo data. Merely introduce your Python code and save the value into the special variable 'result'. Here you might also\n" +"use the special KPI period related variables: 'period_start' (the first date of the period), 'period_end' (the last date\n" +"of the period), 'period_company_id' - res.company object for which Odoo makes calculations at the moment (according to\n" +"KPI period).
  • \n" +"
\n" +"

Basic Measurement Settings

\n" +"

The first 3 calculation types assume that you define how records should be searched and \n" +"which records fields should be used for computations.

\n" +"
    \n" +"
  • Model is an Odoo document type you have in your database, so with which data set you work. For, examples,\n" +"'Sales Order' or 'Task'. Here you can rely not only upon standard objects, but also on Odoo reports. The latter is quite\n" +"useful if indicators are already calculated for existing dashboard (for example, total sales amount in default currency\n" +"from the 'Sales Analysis Report').
  • \n" +"
  • Date fields are required to understand whether a specific document type relates to a considered period, so,\n" +"how to distribute objects by time intervals. For example, for tasks you might use 'create date' to analyze jobs\n" +"registered within this KPI period (e.g. 'Total number of tasks created in January 2021'). It is possible to apply a few\n" +"date fields (e.g. 'Opportunities opened and won in January 2021'). If date fields are not specified, KPI period would\n" +"not influence this basic measurement.
  • \n" +"
  • Filters allow you to restrict records set by any stored field. For example, you may calculate count of only\n" +"won opportunities based on stage settings or only posted customer invoices based on journal entry type and state.
  • \n" +"
  • Measure field is available and required only for calculation types 'Average' and 'Sum'. It defines which\n" +"figure you use for calculations. For example, total amount of Sales Analysis Report to get accumulated sales revenue or\n" +"work hours of tasks to get average spent time per each task.
  • \n" +"
  • Company field would be needed for multi companies environment. According to that field, KPIs are considered\n" +"only withing a KPI period target company. Take into account that records without company stated would be used for\n" +"all companies' KPI calculations.
  • \n" +"
\n" +"

All settings might relate to your custom objects or custom fields, including ones\n" +"created through the interface or the Odoo studio.

\n" +"
\n" +" " +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_help.py:0 +#, python-format +msgid "" +"\n" +"
\n" +"

KPIs (key performance indicators) are measurements which aim to evaluate organizational\n" +"or personal success of a definite activity. Different companies have different KPIs depending on their strategy and\n" +"business area. However, all KPIs have the common core attribute: they must be measurable within a target period.

\n" +"

To that end KPIs allow to construct formulas to retrieve Odoo data sets and process\n" +"those to real figures. Formula preparation is as simple as it is to write down a mathematical expression: just drag and\n" +"drop formula parts in a right order with correct operators.

\n" +"

KPIs, KPI periods, and KPI targets

\n" +"

KPIs represent the list of success figures you may use to plan your company activities.\n" +"Simultaneously, measurements are almost senseless unless you have target values for those KPIs. That is possible only\n" +"within a time-constrained period. 'Sell as much as you can' is not a goal, while 'Generate 100,000 Euro Revenue in the\n" +"year 2021' is a good aim for a sales person, for example. To that end KPI periods are introduced.

\n" +"

A Combination of a KPI and a KPI period results in a KPI target. Exactly with those\n" +"targets you work on the score card interface. For each KPI you would like to manage in this period, you should define\n" +"a planned value to compare those to actual at the end of the period.

\n" +"

So, a KPI itself defines how to compute actual value for period and how to estimate the\n" +"result ('the more the better' or 'the less the better'), but does not assume setting targets. The latter should be done\n" +"for each period.

\n" +"

Formula parts

\n" +"

As variables for formula you may use:

\n" +"

Measurements (KPI measurements, KPI variables) are figures calculated from actual\n" +"Odoo data for a checked period. For example, 'number of quotations of the sales team Europe'.

\n" +"

Among measurements you may also find 2 very specific variables: 'Period Days' and 'Days\n" +"Passed'. Those figures are calculated not from Odoo data, but from the KPI period settings under consideration. 'Period\n" +"Days' is an interval length in days. 'Days Passed' is a length between period start and today (if today is before period\n" +"end; otherwise period end). Those parameters let calculate per-time KPIs, such as, for example, 'Average sales per \n" +"week'.

\n" +"

Constants (KPI constants) are fixed numbers applied globally or for a period.\n" +"Such numbers do not depend on Odoo data. So, they let define strict non-changeable figures which you can't otherwise get\n" +"from Odoo. For example, 'Total investments'.

\n" +"

Other KPIs are results of other KPI formula calculations. That variables allow to\n" +"construct derivative complex calculations and make up hierarchy. For example, you may have KPIs 'Sales count' and\n" +"'Opportunities count', and a derivative KPI 'Opportunity to sales success ratio'.

\n" +"

Variables of any types above might be added to a formula. You may drag and drop as many\n" +"variables as you like (and even use the same variable twice). Just do not forget to add operators in between to make\n" +"correct mathematical expressions. The following operators are available:

\n" +"
    \n" +"
  • \"-\" - subtraction;
  • \n" +"
  • \"+\" - addition;
  • \n" +"
  • \"*\" - multiplication;
  • \n" +"
  • \"/\" - division;
  • \n" +"
  • \"(\", \")\" - to make proper calculation order as it is in Math;
  • \n" +"
  • \"**\" - exponentiation (**2 – squaring; **0.5 – square root extraction);
  • \n" +"
  • Float number.
  • \n" +"
\n" +"

Result appearance

\n" +"

Depending of business logic of KPI formula, the final calculation result might have \n" +"different form:

\n" +"
    \n" +"
  • Simple number: for example, 'Average sales count per week';
  • \n" +"
  • Percentage: for example, 'Sales to opportunities success ratio';
  • \n" +"
  • Monetary: for example, 'Total Sales per period'. Make sure the measurement field you used is in the same\n" +"currency (usually company default currency)!
  • \n" +"
\n" +"

For simple numbers and percentage you may also define result suffix and prefix to make a\n" +"figure nice looking (e.g. add \"%\" as suffix to have \"88%\"). For monetary result type it is recommended\n" +"to define a currency, which symbol would be added to result.

\n" +"

Finally, you may decide how calculation result should be rounded. Available options are\n" +"from 0 to 4 decimal points (1 > 1.2 > 1.23 > 1.235 > 1.2346).

\n" +"

Categories and hierarchy

\n" +"

To make navigation by KPI targets more comfortable, KPIs are combined into KPI\n" +"categories. It let not only quickly search targets inside a scorecard, but it let grant additive access rights. In such\n" +"a way, users would overview only their KPIs structured in sections.

\n" +"

Each KPI might also have a parent. Such hierarchy let organize KPI scorecard with\n" +"indicative padding. For example, 'Total company sales' might have children 'Sales Europe' and 'Sales America'. The\n" +"latter 2 might be further specified by sales persons.

\n" +"

Additive access to KPIs and targets

\n" +"

By default KPIs and there linked targets are available only for users with the right\n" +"'KPI Manager'. Simultaneously, you may grant extra rights for other user groups or/and definite users. To that end it is\n" +"possible to define 'Read Rights' and 'Edit Rights' on KPI category or KPI form views (take into account that KPI\n" +"category rights and KPI own rights are combined!).

\n" +"

Read rights define which user and user groups would be able to observe KPI targets on\n" +"the scorecard interface. For example, you might want to share tasks' targets by persons with related project users in\n" +"order their control themselves.

\n" +"

Edit rights assume sharing an access to set specific targets up. For instance, you may\n" +"find it a good idea to involve sales manager to set sub targets for their sales team.

\n" +"

Take into account: all security settings are additive and they are not restrictive. KPI\n" +"managers would have full rights for all KPIs disregarding those settings, while other users would have rights only to\n" +"KPIs which settings (or category settings) allow them so.

\n" +"
\n" +" " +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_help.py:0 +#, python-format +msgid "" +"\n" +"

A KPI target is your plan for this KPI for a given period. By setting up a target\n" +"value, you indicate which result you would like to achieve by the end of the period.

\n" +"

KPI targets actual values are re-calculated regularly (not in real time) and\n" +"automatically by the Odoo cron job. Alternatively, you may press the button 'Calculate' on the left navigation bar.

\n" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_help.py:0 +#, python-format +msgid "" +"\n" +"

The action removes all current targets and copies targets from a chosen period. After \n" +"that action you would be still able to modify scorecard: change targets' values, delete certain KPI targets, or add new\n" +"ones.

\n" +" " +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_scorecard_line_view_kanban +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_scorecard_line_view_kanban +msgid "#{record.computation_error.raw_value}" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_scorecard_line_view_kanban +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_scorecard_line_view_kanban +msgid "#{record.description.raw_value and record.description.raw_value or ''}" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_item.py:0 +#, python-format +msgid "" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__access_user_ids +msgid "Access Users" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__data_source__achievement +msgid "Achievement" +msgstr "انجاز" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__active +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_constant__active +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__active +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__active +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__active +msgid "Active" +msgstr "نشط" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__edit_rights +msgid "Active User Editor" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#. openerp-web +#: code:addons/kpi_scorecard/models/kpi_period.py:0 +#: code:addons/kpi_scorecard/static/src/xml/kpi_kanban.xml:0 +#: code:addons/kpi_scorecard_odex/models/kpi_scorecard_line.py:0 +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__formatted_actual_value +#, python-format +msgid "Actual" +msgstr "المحقق" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__actual_value +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_scorecard_line_view_kanban +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_scorecard_line_view_kanban +msgid "Actual Value" +msgstr "المحقق" + +#. module: kpi_scorecard +#: model_terms:ir.actions.act_window,help:kpi_scorecard.kpi_period_action +msgid "Add a new period to set KPI targets" +msgstr "" + +#. module: kpi_scorecard +#: model_terms:ir.actions.act_window,help:kpi_scorecard.kpi_item_action +msgid "Add new KPI to measure performance" +msgstr "" + +#. module: kpi_scorecard +#: model_terms:ir.actions.act_window,help:kpi_scorecard.kpi_constant_action +msgid "Add new company constants which are used for KPI calculations" +msgstr "" + +#. module: kpi_scorecard +#: model_terms:ir.actions.act_window,help:kpi_scorecard.kpi_measure_action +msgid "" +"Add new low-level measurements which are used to distinguish KPI calculations variables.\n" +" For example, won opportunities count, total sales, etc." +msgstr "" + +#. module: kpi_scorecard +#: model_terms:ir.actions.act_window,help:kpi_scorecard.kpi_measure_item_action +msgid "" +"Add new measurements (variables) to calculate KPIs.\n" +" For example, won opportunities count for sales team 'Europe', total sales conducted by John Brown, etc." +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__formula_warning +msgid "Alert" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__all_parent_ids +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__all_parents +msgid "All Parents" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__user_group_ids +msgid "Allowed User Groups" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__user_ids +msgid "Allowed Users" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__measurement_periodic__annually +msgid "Annually" +msgstr "سنوي" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_category_view_search +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_constant_view_search +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_item_view_search +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_item_view_search +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_view_search +msgid "Archived" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item__automated_weight +msgid "Automated Weight" +msgstr "الوزن تلقائيا" + +#. module: kpi_scorecard +#: model:ir.model.fields.selection,name:kpi_scorecard.selection__kpi_measure__measure_type__average +msgid "Average of records field" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.actions.act_window,name:kpi_scorecard.kpi_measure_action +#: model:ir.ui.menu,name:kpi_scorecard.menu_kpi_basic_measures +msgid "Basic Measurements" +msgstr "التكامل" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_constant_view_form +msgid "By Periods" +msgstr "بالفترة" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_kanban.xml:0 +#, python-format +msgid "Calculate" +msgstr "حساب" + +#. module: kpi_scorecard +#: model:ir.actions.server,name:kpi_scorecard.cron_recalculate_kpi_periods_ir_actions_server +#: model:ir.cron,cron_name:kpi_scorecard.cron_recalculate_kpi_periods +#: model:ir.cron,name:kpi_scorecard.cron_recalculate_kpi_periods +msgid "Calculate KPIs" +msgstr "" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_copy_template_wizard_form_view +msgid "Cancel" +msgstr "الغاء" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_kanban.xml:0 +#, python-format +msgid "Categories" +msgstr "الاهداف" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__category_id +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__category_id +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_item_view_search +msgid "Category" +msgstr "الاهداف" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_scorecard_line_view_kanban +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_scorecard_line_view_kanban +msgid "Change Target" +msgstr "تغيير المستهدف" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__child_ids +msgid "Child Categories" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__child_ids +msgid "Child KPIs" +msgstr "" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_kanban.xml:0 +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_period_view_form +#, python-format +msgid "Close Period" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields.selection,name:kpi_scorecard.selection__kpi_period__state__closed +msgid "Closed" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_category__code +msgid "Code" +msgstr "الكود" + +#. module: kpi_scorecard +#: model:ir.model,name:kpi_scorecard.model_res_company +msgid "Companies" +msgstr "شركات" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__company_id +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_constant__company_id +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__company_id +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__company_id +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__company_id +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__company_id +msgid "Company" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__company_field_id +msgid "Company Field" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__company_field_name +msgid "Company Field Name" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_res_config_settings__kpi_company_id +msgid "Company for KPI settings" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_measure_item.py:0 +#, python-format +msgid "" +"Computation Error: KPI is not correctly defined. Perhaps, the related module was uninstalled or \n" +" field was removed. Please check basic measurements involved in formula" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_measure.py:0 +#, python-format +msgid "" +"Computation Error: Python code is incorrect: it doesn't contain 'result' key" +" word" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_measure.py:0 +#, python-format +msgid "" +"Computation Error: Python code is incorrect: it returns not number but {}" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_item.py:0 +#, python-format +msgid "Computation Error: the formula is empty" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_item.py:0 +#: code:addons/kpi_scorecard/models/kpi_measure.py:0 +#, python-format +msgid "Computation Error: {}" +msgstr "" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_scorecard_line_view_search +msgid "Computation Errors" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model,name:kpi_scorecard.model_res_config_settings +msgid "Config Settings" +msgstr "ضبط الاعدادات" + +#. module: kpi_scorecard +#: model:ir.ui.menu,name:kpi_scorecard.menu_kpi_conf +msgid "Configuration" +msgstr "الاعدادات" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.res_config_settings_view_form +msgid "Configure cron job" +msgstr "" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.res_config_settings_view_form +msgid "" +"Configure when and how frequent KPIs actual values should be re-calculated" +msgstr "" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_formula.xml:0 +#: model:ir.actions.act_window,name:kpi_scorecard.kpi_constant_action +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__constant_ids +#: model:ir.ui.menu,name:kpi_scorecard.menu_kpi_constants +#, python-format +msgid "Constants" +msgstr "ادخال القياس" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__template_id +msgid "Copy targets from" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields.selection,name:kpi_scorecard.selection__kpi_measure__measure_type__count +msgid "Count of records" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__create_uid +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_constant__create_uid +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_copy_template__create_uid +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__create_uid +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__create_uid +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__create_uid +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__create_uid +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period_value__create_uid +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__create_uid +msgid "Created by" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__create_date +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_constant__create_date +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_copy_template__create_date +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__create_date +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__create_date +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__create_date +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__create_date +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period_value__create_date +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__create_date +msgid "Created on" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__currency_id +msgid "Currency" +msgstr "العملة" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__measurement_method__data_entry +msgid "Data entry" +msgstr "ادخال بيانات" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item__data_source +msgid "Data source" +msgstr "مصدر البيانات" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__date_field_name +msgid "Date Field Name" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__date_field_ids +msgid "Date Fields" +msgstr "" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/models/kpi_item.py:0 +#: code:addons/kpi_scorecard/static/src/xml/kpi_formula.xml:0 +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__period_passed +#, python-format +msgid "Days Passed" +msgstr "" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_formula.xml:0 +#, python-format +msgid "" +"Days of periods which are already in the Past. If period is not yet started " +"- 1. If the whole period is in the Past - period length in days" +msgstr "" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.res_config_settings_view_form +msgid "" +"Define how to distinguish similar periods. For example, 7-days periods might be\n" +" compared to 5-days and 9-days periods. Then, tolerance would be 2. If you have\n" +" monthly or quartely periods you should have at least 3-days tolerance" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_scorecard_line_view_kanban +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_scorecard_line_view_kanban +msgid "Delete Target" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_item.py:0 +#, python-format +msgid "Details" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__data_source__direct_data +msgid "Direct Data" +msgstr "بيانات مباشرة" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_constant__display_name +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_copy_template__display_name +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_help__display_name +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__display_name +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__display_name +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__display_name +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period_value__display_name +#: model:ir.model.fields,field_description:kpi_scorecard.field_res_company__display_name +#: model:ir.model.fields,field_description:kpi_scorecard.field_res_config_settings__display_name +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_category__display_name +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item__display_name +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_scorecard_line__display_name +msgid "Display Name" +msgstr "الاسم المعروض" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/js/scorecard_kanbancontroller.js:0 +#, python-format +msgid "" +"Do you really want to close the period? Actual values by its targets would " +"be frozen then." +msgstr "" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/js/scorecard_kanbancontroller.js:0 +#, python-format +msgid "Do you really want to delete this target?" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__kpi_help_dummy +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_constant__kpi_help_dummy +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_copy_template__kpi_help_dummy +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_help__kpi_help_dummy +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__kpi_help_dummy +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__kpi_help_dummy +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__kpi_help_dummy +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__kpi_help_dummy +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__kpi_help_dummy +msgid "Dummy Help" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_category_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_item_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_item_view_form +msgid "Edit Rights" +msgstr "صلاحية التعديل" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__edit_access_user_ids +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__edit_access_user_ids +msgid "Edit Rights Access Users" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__edit_user_ids +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__edit_user_ids +msgid "Edit Rights Allowed Users" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__edit_user_group_ids +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__edit_user_group_ids +msgid "Edit Rights User Groups" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__kpi_type__effectiveness +msgid "Effectiveness" +msgstr "فاعلية" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__kpi_type__efficiency +msgid "Efficiency" +msgstr "كفاءة" + +#. module: kpi_scorecard +#: model:ir.model.fields.selection,name:kpi_scorecard.selection__kpi_scorecard_line__result__error +msgid "Error" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields.selection,name:kpi_scorecard.selection__kpi_measure__measure_type__py_code +msgid "Execute Python code" +msgstr "" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_kanban.xml:0 +#, python-format +msgid "Export Scorecard" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item__external_bench_ids +msgid "External Benchmarking" +msgstr "جهة المقارنة المرجعية الخارجية" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__domain +msgid "Extra Filters" +msgstr "" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_item_view_form +msgid "Extra Targets Security" +msgstr "" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_scorecard_line_view_search +msgid "Failed Targets" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields.selection,name:kpi_scorecard.selection__kpi_scorecard_line__result__failure +msgid "Failure" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__domain +msgid "Filters" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__kpi_type__financial +msgid "Financial" +msgstr "مالي" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__formula +msgid "Formula" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_constant__target_value +msgid "Global Value" +msgstr "" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_category_view_search +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_constant_view_search +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_item_view_search +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_item_view_search +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_view_search +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_period_view_search +msgid "Group By" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__help_notes +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_constant__help_notes +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_copy_template__help_notes +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_help__help_notes +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__help_notes +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__help_notes +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__help_notes +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__help_notes +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__help_notes +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_category_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_constant_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_item_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_item_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_period_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_item_view_form +msgid "Help" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_scorecard_line_view_kanban +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_scorecard_line_view_kanban +msgid "History" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_res_company__kpi_history_tolerance +#: model:ir.model.fields,field_description:kpi_scorecard.field_res_config_settings__kpi_history_tolerance +msgid "History Tolerance" +msgstr "" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_kanban.xml:0 +#, python-format +msgid "History by similar periods" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_constant__id +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_copy_template__id +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_help__id +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__id +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__id +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__id +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period_value__id +#: model:ir.model.fields,field_description:kpi_scorecard.field_res_company__id +#: model:ir.model.fields,field_description:kpi_scorecard.field_res_config_settings__id +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_category__id +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item__id +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_scorecard_line__id +msgid "ID" +msgstr "المُعرف" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_measure.py:0 +#, python-format +msgid "In order to activate the KPI, please install the module for {}" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__kpi_type_region__inputs +msgid "Inputs" +msgstr "مدخلات" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__existing_kpi +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__existing_kpi +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_view_search +msgid "Installed" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__kpi_domain__institute +msgid "Institutional Accreditation" +msgstr "الاعتماد المؤسسي" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item__internal_bench_ids +msgid "Internal Benchmarking" +msgstr "جهة المقارنة المرجعية الداخلية" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_category.py:0 +#, python-format +msgid "It is not allowed to make recursions!" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/res_config_settings.py:0 +#, python-format +msgid "Job: Calculate KPIs" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: code:addons/kpi_scorecard/models/kpi_period.py:0 +#: code:addons/kpi_scorecard_odex/models/kpi_scorecard_line.py:0 +#: model:ir.actions.act_window,name:kpi_scorecard.kpi_item_action +#: model:ir.model,name:kpi_scorecard_odex.model_kpi_item +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__kpi_id +#: model:ir.ui.menu,name:kpi_scorecard.menu_kpi_main +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_item_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_item_view_form +#, python-format +msgid "KPI" +msgstr "المؤشرات" + +#. module: kpi_scorecard +#: model:ir.actions.act_window,name:kpi_scorecard.kpi_category_action +#: model:ir.ui.menu,name:kpi_scorecard.menu_kpi_categories +msgid "KPI Categories" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model:ir.model,name:kpi_scorecard_odex.model_kpi_category +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_category_view_form +msgid "KPI Category" +msgstr "الهدف التشغيلي" + +#. module: kpi_scorecard_odex +#: code:addons/kpi_scorecard_odex/models/kpi_scorecard_line.py:0 +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item__code +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_scorecard_line__code +#, python-format +msgid "KPI Code" +msgstr "كود المؤشر" + +#. module: kpi_scorecard +#: model:ir.model,name:kpi_scorecard.model_kpi_constant +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period_value__constant_id +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_constant_view_form +msgid "KPI Constant" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item__kpi_domain +msgid "KPI Domain" +msgstr "مجال المؤشر" + +#. module: kpi_scorecard +#: model:ir.model,name:kpi_scorecard.model_kpi_help +msgid "KPI Help" +msgstr "" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/js/scorecard_kanbancontroller.js:0 +#, python-format +msgid "KPI History" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.module.category,name:kpi_scorecard.module_category_kpi +msgid "KPI Management" +msgstr "" + +#. module: kpi_scorecard +#: model:res.groups,name:kpi_scorecard.group_kpi_admin +msgid "KPI Manager" +msgstr "" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_view_form +msgid "KPI Measure" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model,name:kpi_scorecard.model_kpi_measure +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_item_view_form +msgid "KPI Measurement" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model,name:kpi_scorecard.model_kpi_measure_item +msgid "KPI Measurement (Variable)" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item__kpi_owner_id +msgid "KPI Owner" +msgstr "مالك الموشر" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model:ir.model,name:kpi_scorecard.model_kpi_period +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item__kpi_period +msgid "KPI Period" +msgstr "مدة المؤشر" + +#. module: kpi_scorecard +#: model:ir.model,name:kpi_scorecard.model_kpi_period_value +msgid "KPI Period Value" +msgstr "" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/js/scorecard_kanbanview.js:0 +#: model:ir.actions.act_window,name:kpi_scorecard.kpi_scorecard_line_action +#: model:ir.ui.menu,name:kpi_scorecard.menu_kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.res_config_settings_view_form +#, python-format +msgid "KPI Scorecard" +msgstr "تقرير مؤشرات اﻷداء" + +#. module: kpi_scorecard_odex +#: model:ir.model,name:kpi_scorecard_odex.model_kpi_scorecard_line +msgid "KPI Target" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__line_ids +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item__line_ids +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_item_view_form +msgid "KPI Targets" +msgstr "المستهدف" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__measure_type +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__measure_type +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item__kpi_type +msgid "KPI Type" +msgstr "نمط الموشر" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item__kpi_type_region +msgid "KPI Type By Region" +msgstr "نوع المؤشر حسب المنطقة" + +#. module: kpi_scorecard +#: model:ir.ui.menu,name:kpi_scorecard.menu_kpi_kpi +msgid "KPIs" +msgstr "المؤشرات" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_category_view_form +msgid "KPIs Targets Security" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__last_recalculation_date +msgid "Last KPI Calculation" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_constant____last_update +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_copy_template____last_update +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_help____last_update +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure____last_update +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item____last_update +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period____last_update +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period_value____last_update +#: model:ir.model.fields,field_description:kpi_scorecard.field_res_company____last_update +#: model:ir.model.fields,field_description:kpi_scorecard.field_res_config_settings____last_update +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_category____last_update +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item____last_update +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_scorecard_line____last_update +msgid "Last Modified on" +msgstr "آخر تعديل في" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__write_uid +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_constant__write_uid +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_copy_template__write_uid +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__write_uid +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__write_uid +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__write_uid +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__write_uid +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period_value__write_uid +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__write_date +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_constant__write_date +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_copy_template__write_date +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__write_date +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__write_date +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__write_date +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__write_date +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period_value__write_date +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__write_date +msgid "Last Updated on" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__computation_error +msgid "Logs" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,help:kpi_scorecard.field_kpi_measure__py_code +msgid "" +"Make sure the 'result' is defined and it contains the new current value." +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__measure_field_id +msgid "Measure Field" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__measure_field_name +msgid "Measure Field Name" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__measure_id +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_item_view_search +msgid "Measurement" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item__measurement_method +msgid "Measurement Method" +msgstr "طريقة القياس " + +#. module: kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item__measurement_periodic +msgid "Measurement Periodicity" +msgstr "دورية القياس" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_view_search +msgid "Measurement Type" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_formula.xml:0 +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__measures_ids +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__item_ids +#: model:ir.ui.menu,name:kpi_scorecard.menu_kpi_measurements_general +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_item_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_item_view_form +#, python-format +msgid "Measurements" +msgstr "المقاييس" + +#. module: kpi_scorecard +#: model:ir.actions.act_window,name:kpi_scorecard.kpi_measure_item_action +#: model:ir.ui.menu,name:kpi_scorecard.menu_kpi_measures +msgid "Measurements (Variables)" +msgstr "ممقاييس المؤشرات" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__measures_len +msgid "Measurements Count" +msgstr "" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_period_view_form +msgid "Misc" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__model_id +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__model_id +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_item_view_search +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_view_search +msgid "Model" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__model_name +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__model_name +msgid "Model Name" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields.selection,name:kpi_scorecard.selection__kpi_item__result_appearance__monetory +msgid "Monetary" +msgstr "نقدي" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: code:addons/kpi_scorecard/models/kpi_scorecard_line.py:0 +#: code:addons/kpi_scorecard_odex/models/kpi_scorecard_line.py:0 +#, python-format +msgid "N/A" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__name +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_constant__name +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__name +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__name +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__name +msgid "Name" +msgstr "الاسم" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_kanban.xml:0 +#, python-format +msgid "New Period" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: code:addons/kpi_scorecard/models/kpi_period.py:0 +#: code:addons/kpi_scorecard_odex/models/kpi_scorecard_line.py:0 +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__description +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_constant__description +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__description +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__description +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__description +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_category_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_constant_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_item_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_view_form +#, python-format +msgid "Notes" +msgstr "ملاحظات" + +#. modules: kpi_scorecard,kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__description +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_item_view_form +msgid "Notes" +msgstr "وصف المؤشر" + +#. module: kpi_scorecard +#: model:ir.model.fields.selection,name:kpi_scorecard.selection__kpi_item__result_appearance__number +msgid "Number" +msgstr "عدد" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_period_view_search +msgid "Open" +msgstr "" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/js/scorecard_kanbancontroller.js:0 +#, python-format +msgid "Open New Period" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields.selection,name:kpi_scorecard.selection__kpi_period__state__open +msgid "Opened" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_category__type__op_goal +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_item_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_item_view_search +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_item_view_tree +msgid "Operational Goal" +msgstr "هدف تشغيلي" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_formula.xml:0 +#, python-format +msgid "Operators" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__data_source__poll +msgid "Opinion Polls" +msgstr "استطلاعات رأي" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_category__type__other +msgid "Other" +msgstr "اخرى" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_formula.xml:0 +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__kpi_ids +#, python-format +msgid "Other KPIs" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_item.py:0 +#, python-f.ormat +msgid "" +"Other KPIs used in formula depends on this KPI. Calculation is impossible" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__kpi_type_region__outputs +msgid "Outputs" +msgstr "مخرجات" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__parent_id +msgid "Parent Category" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__parent_id +msgid "Parent KPI" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__parent_id +msgid "Parent Period" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields.selection,name:kpi_scorecard.selection__kpi_item__result_appearance__percentage +msgid "Percentage" +msgstr "نسبة" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_kanban.xml:0 +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period_value__period_id +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__period_id +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_period_view_form +#, python-format +msgid "Period" +msgstr "" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/models/kpi_item.py:0 +#: code:addons/kpi_scorecard/static/src/xml/kpi_formula.xml:0 +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__period_length +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__period_length +#, python-format +msgid "Period Days" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__date_end +msgid "Period End" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__date_start +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_period_view_search +msgid "Period Start" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_period.py:0 +#: model:ir.model.constraint,message:kpi_scorecard.constraint_kpi_period_dates_check +#, python-format +msgid "Period end should be after period start" +msgstr "" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_formula.xml:0 +#, python-format +msgid "Period length in days" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_period_value.py:0 +#: model:ir.model.constraint,message:kpi_scorecard.constraint_kpi_period_value_period_constant_id_uniq +#, python-format +msgid "Period should be unique per each constant!" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__measurement_periodic__periodical +msgid "Periodical" +msgstr "فصلي" + +#. module: kpi_scorecard +#: model:ir.actions.act_window,name:kpi_scorecard.kpi_period_action +#: model:ir.ui.menu,name:kpi_scorecard.menu_kpi_period +msgid "Periods" +msgstr "الفترات" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_category__type__pillar +msgid "Pillar" +msgstr "ركيزة" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__kpi_type_region__processes +msgid "Processes" +msgstr "عمليات" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__kpi_type__productivity +msgid "Productivity" +msgstr "إنتاجية" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item__program_id +msgid "Program" +msgstr "البرنامج" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__kpi_domain__program +msgid "Program Accreditation" +msgstr "اعتماد برامجي" + +#. module: kpi_scorecard_odex +#: code:addons/kpi_scorecard_odex/models/kpi_scorecard_line.py:0 +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_scorecard_line__progress +#, python-format +msgid "Progress" +msgstr "الانجاز" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__py_code +msgid "Python Code" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__kpi_type__quality +msgid "Quality" +msgstr "جودة" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_kanban.xml:0 +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_period_view_form +#, python-format +msgid "Re-Open Period" +msgstr "" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_scorecard_line_view_search +msgid "Reached Targets" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_category_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_item_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_item_view_form +msgid "Read Rights" +msgstr "صلاحية اطلاع" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__access_user_ids +msgid "Read Rights Access Users" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__user_group_ids +msgid "Read Rights User Groups" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__user_ids +msgid "Read Rights Users" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__name +msgid "Reference" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__result +msgid "Result" +msgstr "النتيجة" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__result_preffix +msgid "Result Prefix" +msgstr "بادئة" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__result_suffix +msgid "Result Suffix" +msgstr "لاحقة" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__result_appearance +msgid "Result Type" +msgstr "نوع النتيجة" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__result_rounding +msgid "Rounding Decimals" +msgstr "التقريب" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__kpi_domain__research +msgid "Scientific Research" +msgstr "البحث العلمي" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_formula.xml:0 +#: code:addons/kpi_scorecard/static/src/xml/kpi_formula.xml:0 +#: code:addons/kpi_scorecard/static/src/xml/kpi_formula.xml:0 +#, python-format +msgid "Search" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__kpi_type__security +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_item_view_form +msgid "Security" +msgstr "الصلاحيات" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.res_config_settings_view_form +msgid "Select company to configure KPI management settings" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_category__sequence +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_constant__sequence +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__sequence +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure__sequence +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_measure_item__sequence +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__sequence +msgid "Sequence" +msgstr "متسلسل" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/js/scorecard_kanbancontroller.js:0 +#: code:addons/kpi_scorecard/static/src/xml/kpi_kanban.xml:0 +#, python-format +msgid "Set Target" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_constant__periods_ids +msgid "Set for periods" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model:ir.actions.act_window,name:kpi_scorecard.res_config_settings_kpi_scorecard_action +#: model:ir.ui.menu,name:kpi_scorecard.menu_kpi_settings +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_item_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_item_view_form +msgid "Settings" +msgstr "الاعدادات" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_res_company__show_kpi_help +#: model:ir.model.fields,field_description:kpi_scorecard.field_res_config_settings__show_kpi_help +msgid "Show Help Tabs" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period__state +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_period_view_search +msgid "State" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_category__type__st_goal +msgid "Strategic Goal" +msgstr "هدف استراتيجي" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_kanban.xml:0 +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_copy_template_wizard_form_view +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_period_view_form +#, python-format +msgid "Substitute Targets" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_copy_template__template_id +msgid "Substitute Targets With" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.actions.act_window,name:kpi_scorecard.kpi_copy_template_action +msgid "Substitute Targets with Targets from Another Period" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: code:addons/kpi_scorecard_odex/models/kpi_scorecard_line.py:0 +#: model:ir.model.fields.selection,name:kpi_scorecard.selection__kpi_scorecard_line__result__success +#, python-format +msgid "Success" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_item__result_type +msgid "Success Criteria" +msgstr "معايير النجاح" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_scorecard_line__target_value +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_scorecard_line_view_kanban +msgid "Success Value" +msgstr "نجاح المؤشر" + +#. module: kpi_scorecard +#: model:ir.model.fields.selection,name:kpi_scorecard.selection__kpi_measure__measure_type__sum +msgid "Sum of records field" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#. openerp-web +#: code:addons/kpi_scorecard/models/kpi_period.py:0 +#: code:addons/kpi_scorecard/static/src/xml/kpi_kanban.xml:0 +#: code:addons/kpi_scorecard_odex/models/kpi_scorecard_line.py:0 +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_scorecard_line__formatted_target_value +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_scorecard_line__formatted_planed_value +#, python-format +msgid "Target" +msgstr "المستهدف" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_period_value__target_value +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_scorecard_line__planed_value +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_scorecard_line_view_kanban +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_scorecard_line_view_kanban +msgid "Target Value" +msgstr "المستهدف" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_scorecard_line.py:0 +#: model:ir.model.constraint,message:kpi_scorecard.constraint_kpi_scorecard_line_period_kpi_uniq +#, python-format +msgid "Target for this KPI is already set for this period" +msgstr "" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_period_view_form +msgid "Targets" +msgstr "" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_kanban.xml:0 +#, python-format +msgid "Targets by all periods" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_category_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_constant_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_item_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_item_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_measure_view_form +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_item_view_form +msgid "Technical" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model,name:kpi_scorecard.model_kpi_copy_template +msgid "Template Targets Replace" +msgstr "" + +#. modules: kpi_scorecard, kpi_scorecard_odex +#: code:addons/kpi_scorecard/models/kpi_period.py:0 +#: code:addons/kpi_scorecard_odex/models/kpi_scorecard_line.py:0 +#, python-format +msgid "" +"The Python library xlsxwriter is installed. Contact your system " +"administrator" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_item.py:0 +#, python-format +msgid "The formula is empty" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_item.py:0 +#, python-format +msgid "The formula might be incorrect: {}" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_item.py:0 +#, python-format +msgid "The formula might rely upon incorrect KPI: {}.>> {}" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_item.py:0 +#, python-format +msgid "The formula uses obsolete measurement: {}" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields.selection,name:kpi_scorecard.selection__kpi_item__result_type__less +msgid "The less the better" +msgstr "اﻷقل اﻷفضل" + +#. module: kpi_scorecard +#: model:ir.model.fields.selection,name:kpi_scorecard.selection__kpi_item__result_type__more +msgid "The more the better" +msgstr "اﻷكثر اﻷفضل" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_item.py:0 +#, python-format +msgid "There are KPIs which depend on this KPI: {}. Delete them before" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_measure_item.py:0 +#, python-format +msgid "" +"There are KPIs which depend on this MEASUREMENT: {}. Delete them before" +msgstr "" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_constant.py:0 +#, python-format +msgid "There are KPIs which depend on this constant: {}. Delete them before" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,field_description:kpi_scorecard.field_kpi_copy_template__period_id +msgid "This Period" +msgstr "" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.res_config_settings_view_form +msgid "Turn on / off help notes on KPI settings objects" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_category__type +msgid "Type" +msgstr "نوع" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__kpi_domain__university +msgid "University Strategy" +msgstr "استراتيجية الجامعة" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/js/scorecard_kanbancontroller.js:0 +#, python-format +msgid "Update Target" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,help:kpi_scorecard.field_kpi_constant__target_value +msgid "Value used in case this constant is not applied for a target period" +msgstr "" + +#. module: kpi_scorecard_odex +#: code:addons/kpi_scorecard_odex/models/kpi_scorecard_line.py:0 +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_category__weight +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_item__weight +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_scorecard_line__weight +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_item_view_tree +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_scorecard_line_view_kanban +#, python-format +msgid "Weight" +msgstr "الوزن" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields,field_description:kpi_scorecard_odex.field_kpi_scorecard_line__weight_progress +msgid "Weight Progress" +msgstr "الوزن المحقق" + +#. module: kpi_scorecard_odex +#: code:addons/kpi_scorecard_odex/models/kpi_scorecard_line.py:0 +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_scorecard_line_view_kanban +#, python-format +msgid "Weight progress" +msgstr "الوزن المحقق" + +#. module: kpi_scorecard +#: code:addons/kpi_scorecard/models/kpi_item.py:0 +#, python-format +msgid "You cannot create recursive KPIs." +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.customer_invoice_all +msgid "[account] Posted Customer Invoices: Count" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.customer_invoice_amount_all +#: model:kpi.measure,name:kpi_scorecard.vendor_bills_amount_all +msgid "[account] Posted Customer Invoices: Total" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.vendor_invoice_all +msgid "[account] Posted Vendor Bills: Count" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.crm_lead_all +msgid "[crm] Leads and Opportunities: Count" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.crm_lead_leads_only +msgid "[crm] Leads: Count" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.crm_lead_opportunities_days_to_assign +msgid "[crm] Opportunities: Average Days to Assign" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.crm_lead_opportunities_days_to_close +msgid "[crm] Opportunities: Average Days to Close" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.crm_lead_opportunities_expected_revenue +msgid "[crm] Opportunities: Average Expected Revenue" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.crm_lead_opportunities_sale_average +msgid "[crm] Opportunities: Average of Sale Orders" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.crm_lead_opportunities_only +msgid "[crm] Opportunities: Count" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.crm_lead_opportunities_expected_revenue_total +msgid "[crm] Opportunities: Total Expected Revenue" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.crm_lead_opportunities_sale_total +msgid "[crm] Opportunities: Total Sale Orders" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.crm_lead_won_opprotunities +msgid "[crm] Won Opportunities: Count" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.project_task_planned_hours_average +msgid "[project] Tasks: Average Planned Hours" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.project_task_all +msgid "[project] Tasks: Count" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.project_task_planned_hours +msgid "[project] Tasks: Total Planned Hours" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.project_task_working_days_to_assign +msgid "[project] Tasks: Working Days to Assign" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.project_task_working_days_to_close +msgid "[project] Tasks: Working Days to Close" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.sale_order_all_abs +msgid "[sales] All Sale Orders and Quotations: Count" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.sale_order_all +msgid "[sales] Сonfirmed/Done Sale Orders: Count" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.sale_order_delivered_qty +msgid "[sales] Сonfirmed/Done Sale Orders: Delivered Units" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.sale_order_invoiced_qty +msgid "[sales] Сonfirmed/Done Sale Orders: Invoiced Units" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.sale_order_number_of_lines +msgid "[sales] Сonfirmed/Done Sale Orders: Number of Lines" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.sale_order_total +msgid "[sales] Сonfirmed/Done Sale Orders: Total" +msgstr "" + +#. module: kpi_scorecard +#: model:kpi.measure,name:kpi_scorecard.sale_order_total_qty +msgid "[sales]Сonfirmed/Done Sale Orders: Product Units" +msgstr "" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_period_view_form +msgid "e.g. Year 2021" +msgstr "" + +#. module: kpi_scorecard +#. openerp-web +#: code:addons/kpi_scorecard/static/src/xml/kpi_kanban.xml:0 +#, python-format +msgid "if closed, KPI actual values would not be re-calculated any more" +msgstr "" + +#. module: kpi_scorecard_odex +#: model:ir.model.fields.selection,name:kpi_scorecard_odex.selection__kpi_item__measurement_method__integration +msgid "integration" +msgstr "تكامل" + +#. module: kpi_scorecard_odex +#: model_terms:ir.ui.view,arch_db:kpi_scorecard_odex.kpi_item_view_form +msgid "kpiFormula" +msgstr "المعادلة" + +#. module: kpi_scorecard +#: model_terms:ir.ui.view,arch_db:kpi_scorecard.kpi_period_view_form +msgid "to" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,help:kpi_scorecard.field_kpi_item__result_suffix +msgid "would be shown after the result value" +msgstr "" + +#. module: kpi_scorecard +#: model:ir.model.fields,help:kpi_scorecard.field_kpi_item__result_preffix +msgid "would be shown before the result value" +msgstr "" diff --git a/odex25_project/kpi_scorecard_odex/models/__init__.py b/odex25_project/kpi_scorecard_odex/models/__init__.py new file mode 100644 index 000000000..be398e78e --- /dev/null +++ b/odex25_project/kpi_scorecard_odex/models/__init__.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- + + +from . import kpi_category +from . import kpi_item +from . import kpi_scorecard_line +from . import kpi_period +from . import partner_target + + + + + diff --git a/odex25_project/kpi_scorecard_odex/models/kpi_category.py b/odex25_project/kpi_scorecard_odex/models/kpi_category.py new file mode 100644 index 000000000..050b3c913 --- /dev/null +++ b/odex25_project/kpi_scorecard_odex/models/kpi_category.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# (Odex - Extending the base module). +# Copyright (C) 2024 Expert Co. Ltd. (). +# +############################################################################## + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class kpi_category(models.Model): + + _inherit = "kpi.category" + + code = fields.Char(string="Code") + weight = fields.Float(string="Weight") + type = fields.Selection([ + ("pillar", "Pillar"), + ("st_goal", "Strategic Goal"), + ("op_goal", "Operational Goal"), + ("other", "Other")],string="Type", default="op_goal") + + def name_get(self): + return super(models.Model, self).name_get() + + + def write(self, data): + res = super(kpi_category, self).write(data) + if data.get('weight'): + self.env["kpi.item"].compute_automated_weight(self) + return res + + diff --git a/odex25_project/kpi_scorecard_odex/models/kpi_item.py b/odex25_project/kpi_scorecard_odex/models/kpi_item.py new file mode 100644 index 000000000..09cb11863 --- /dev/null +++ b/odex25_project/kpi_scorecard_odex/models/kpi_item.py @@ -0,0 +1,128 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# (Odex - Extending the base module). +# Copyright (C) 2024 Expert Co. Ltd. (). +# +############################################################################## + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class kpi_item(models.Model): + + _inherit = "kpi.item" + + code = fields.Char(string="KPI Code", required=True) + weight = fields.Float(string="Weight") + automated_weight = fields.Boolean(string="Automated Weight", default=True) + kpi_domain = fields.Selection([ + ("university", "University Strategy"), + ("research", "Scientific Research"), + ("institute", "Institutional Accreditation"), + ("program", "Program Accreditation")], string="KPI Domain", required=True, default="university") + program_id = fields.Many2one("kpi.category", string="Program") + kpi_type = fields.Selection([ + ("efficiency", "Efficiency"), + ("effectiveness", "Effectiveness"), + ("productivity", "Productivity"), + ("financial", "Financial"), + ("quality", "Quality"), + ("security", "Security")], string="KPI Type", required=True, default="efficiency") + kpi_type_region = fields.Selection([ + ("inputs", "Inputs"), + ("processes", "Processes"), + ("outputs", "Outputs"),], string="KPI Type By Region", required=True, default="inputs") + data_source = fields.Selection([ + ("achievement", "Achievement"), + ("direct_data", "Direct Data"), + ("poll", "Opinion Polls"),], string="Data source", required=True, default="achievement") + measurement_method = fields.Selection([ + ("data_entry", "Data entry"), + ("integration", "integration"),], string="Measurement Method", required=True, default="data_entry") + measurement_periodic= fields.Selection([ + ("periodical", "Periodical"), + ("annually", "Annually"),], string="Measurement Periodicity", required=True, default="annually") + kpi_owner_id = fields.Many2one("res.partner", string="KPI Owner") + internal_bench_ids = fields.Many2many("res.partner", + "res_partner_kpi_item_rel_internal", + "res_partner_id", "kpi_item_id", string="Internal Benchmarking") + external_bench_ids = fields.Many2many("res.partner", + "res_partner_kpi_item_rel_external", + "res_partner_id", "kpi_item_id", string="External Benchmarking") + + kpi_period = fields.Selection([ + ("1", "1"), + ("2", "2"), + ("3", "3"), + ("4", "4"),("5", "5") ], string="KPI Period", default="5") + + line_ids = fields.One2many("kpi.scorecard.line", "kpi_id", string="KPI Targets", copy=True) + + + def compute_automated_weight(self, category_ids): + for category in category_ids: + goal_kpis = self.env["kpi.item"].sudo().search([ ("category_id", "=", category.id),("automated_weight", "=", True)]) + goal_kpis_edit = self.env["kpi.item"].sudo().search([ ("category_id", "=", category.id),("automated_weight", "=", False)]) + goal_weight = category.weight - sum(goal_kpis_edit.mapped('weight')) + if len(goal_kpis) > 0: + weight = round(goal_weight / len(goal_kpis) , 2) + goal_kpis.write({"weight": weight}) + + @api.model + def create(self, data): + res = super(kpi_item, self).create(data) + category_ids =[] + for kpi in res: + category_ids.append(kpi.category_id) + self.compute_automated_weight(category_ids) + return res + + def write(self, data): + category_ids =[] + for kpi in self: + if data.get('category_id'): + category_ids.append(kpi.category_id) + res = super(kpi_item, self).write(data) + if data.keys() & {'automated_weight', 'active', 'category_id'}: + for kpi in self: + category_ids.append(kpi.category_id) + if data.get('weight') and not data.get('automated_weight'): + for kpi in self: + if not kpi.automated_weight: + category_ids.append(kpi.category_id) + self.compute_automated_weight(category_ids) + return res + + def unlink(self): + category_ids =[] + for kpi in self: + category_ids.append(kpi.category_id) + res = super(kpi_item, self).unlink() + self.compute_automated_weight(category_ids) + return res + + @api.onchange('category_id') + def onchange_category_id(self): + ''' + This function generates the kpi code automatically with the possibility to modify it + ''' + if self.category_id and self.category_id.code: + parent_code = self.category_id.code + count = len (self.search([("category_id", "=", self.category_id.id)])) or 1 + serial = int(count) + added = 0 + code = '' + while True: + serial += added + code_length = len(str(parent_code)) + len(str(serial)) + code = parent_code +str(serial) + if not self.search([('code','=',code)]): + break + added += 1 + self.code = code + + + + diff --git a/odex25_project/kpi_scorecard_odex/models/kpi_period.py b/odex25_project/kpi_scorecard_odex/models/kpi_period.py new file mode 100644 index 000000000..056d05763 --- /dev/null +++ b/odex25_project/kpi_scorecard_odex/models/kpi_period.py @@ -0,0 +1,111 @@ +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError, UserError +import base64 +import logging +import tempfile + +_logger = logging.getLogger(__name__) + +try: + import xlsxwriter +except ImportError: + _logger.warning("Cannot import xlsxwriter") + xlsxwriter = False + + +class kpi_period(models.Model): + _inherit = "kpi.period" + + def name_get(self): + return super(models.Model, self).name_get() + + def action_export_scorecard(self): + """ + The method to prepare the xls table + + Methods: + * _get_xls_table of kpi.scorecard.line + + Returns: + * action of downloading the xlsx table + + Extra info: + * Expected singleton + """ + self.ensure_one() + if not xlsxwriter: + raise UserError(_("The Python library xlsxwriter is installed. Contact your system administrator")) + file_name = u"{}.xlsx".format(self.name_get()[0][1]) + file_path = tempfile.mktemp(suffix='.xlsx') + workbook = xlsxwriter.Workbook(file_path) + main_header_style = workbook.add_format({ + 'bold': True, + 'font_size': 11, + 'border': 1, + 'align': 'center', + 'valign': 'vcenter', + 'bg_color': 'silver', + 'border_color': 'gray', + }) + main_cell_style_dict = { + 'font_size': 11, + 'border': 1, + 'border_color': 'gray', + } + worksheet = workbook.add_worksheet(file_name) + column_keys = [ + {"key": "A", "label": _("KPI Code"), "width": 14}, + {"key": "B", "label": _("KPI"), "width": 60}, + {"key": "C", "label": _("Target"), "width": 14}, + {"key": "D", "label": _("Success"), "width": 14}, + {"key": "E", "label": _("Actual"), "width": 14}, + {"key": "F", "label": _("Progress"), "width": 14}, + {"key": "G", "label": _("Weight"), "width": 14}, + {"key": "H", "label": _("Weight progress"), "width": 14}, + {"key": "I", "label": _("Notes"), "width": 80}, + ] + total_row_number = len(self.line_ids) + cell_values = self.line_ids._get_xls_table() + for ccolumn in column_keys: + ckey = ccolumn.get("key") + # set columns + worksheet.set_column('{c}:{c}'.format(c=ckey), ccolumn.get("width")) + # set header row + worksheet.write("{}1".format(ckey), ccolumn.get("label"), main_header_style) + # set column values + for row_number in range(2, total_row_number + 2): + cell_number = "{}{}".format(ckey, row_number) + cell_value_dict = cell_values.get(cell_number) + cell_value = "" + cell_level = 0 + cell_style = main_cell_style_dict.copy() + if cell_value_dict: + cell_value = cell_value_dict.get("value") + cell_style.update(cell_value_dict.get("style")) + cell_level = cell_value_dict.get("level") or 0 + cell_style = workbook.add_format(cell_style) + if ckey == "A": + cell_style.set_indent(cell_level) + worksheet.write( + cell_number, + cell_value, + cell_style, + ) + worksheet.set_row(0, 24) + workbook.close() + with open(file_path, 'rb') as r: + xls_file = base64.b64encode(r.read()) + att_vals = { + 'name': file_name, + 'type': 'binary', + 'datas': xls_file, + } + attachment_id = self.env['ir.attachment'].create(att_vals) + self.env.cr.commit() + action = { + 'type': 'ir.actions.act_url', + 'url': '/web/content/{}?download=true'.format(attachment_id.id, ), + 'target': 'self', + } + return action + diff --git a/odex25_project/kpi_scorecard_odex/models/kpi_scorecard_line.py b/odex25_project/kpi_scorecard_odex/models/kpi_scorecard_line.py new file mode 100644 index 000000000..0b527965a --- /dev/null +++ b/odex25_project/kpi_scorecard_odex/models/kpi_scorecard_line.py @@ -0,0 +1,216 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# (Odex - Extending the base module). +# Copyright (C) 2024 Expert Co. Ltd. (). +# +############################################################################## +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError, UserError +import base64 +import logging +import tempfile + +_logger = logging.getLogger(__name__) + +try: + import xlsxwriter +except ImportError: + _logger.warning("Cannot import xlsxwriter") + xlsxwriter = False + + +class kpi_scorecard_line(models.Model): + _inherit = "kpi.scorecard.line" + + @api.depends("target_value", "actual_value", "computation_error", "kpi_id", "kpi_id.result_appearance", + "kpi_id.result_preffix", "kpi_id.result_suffix", "kpi_id.result_type") + def _compute_formatted_actual_value(self): + """ + Compute method for formatted_actual_value, result, formatted_target_value + + Methods: + * _return_formated_appearance of kpi.item + """ + for line in self: + kpi_id = line.kpi_id + company_currency = line.period_id.company_id.currency_id + if line.computation_error: + line.formatted_actual_value = _("N/A") + line.result = "error" + line.formatted_target_value = kpi_id._return_formated_appearance( + line.target_value, novalue_change=True, currency=company_currency, + ) + line.formatted_planed_value = kpi_id._return_formated_appearance( + line.planed_value, novalue_change=True, currency=company_currency, + ) + else: + actual_value = line.actual_value + line.formatted_actual_value = kpi_id._return_formated_appearance( + line.actual_value, novalue_change=False, currency=company_currency, + ) + line.formatted_planed_value = kpi_id._return_formated_appearance( + line.planed_value, novalue_change=True, currency=company_currency, + ) + line.formatted_target_value = kpi_id._return_formated_appearance( + line.target_value, novalue_change=True, currency=company_currency, + ) + result_type = kpi_id.result_type + actual_value = line.kpi_id.result_appearance == "percentage" and (actual_value * 100) or actual_value + bigger_result = actual_value >= line.target_value + if result_type == "more": + line.result = bigger_result and "success" or "failure" + elif result_type == "less": + line.result = bigger_result and "failure" or "success" + + weight = fields.Float(string="Weight", related="kpi_id.weight", store=True) + code = fields.Char(string="KPI Code", related="kpi_id.code", store=True) + progress = fields.Float("Progress", compute='_compute_progress_kpi', store=True, group_operator="avg") + weight_progress = fields.Float("Weight Progress", compute='_compute_progress_kpi', store=True, ) + target_value = fields.Float(string="Success Value") + planed_value = fields.Float(string="Target Value") + formatted_planed_value = fields.Char( + string="Target", + compute=_compute_formatted_actual_value, + compute_sudo=True, + store=True, + ) + + pillar_categ_id = fields.Many2one(comodel_name='kpi.category', compute='_compute_parent_category', store=True, ) + strategic_category_id = fields.Many2one(comodel_name='kpi.category', compute='_compute_parent_category', + store=True, ) + plan_progress = fields.Float(string="Planned Progress", compute='_compute_progress_kpi', store=True, + ) + + def get_strategic_category(self, category_id): + """ + Get the last parent category with type 'st_goal' in the chain of categories. + + :param category_id: The initial category for which to find the last 'pillar' parent. + :return: The last Strategic Goal parent category or None if not found. + """ + if category_id.type == 'st_goal': + return category_id + + while category_id.parent_id: + category_id = category_id.parent_id + if category_id.type == 'st_goal': + return category_id + return None + + def get_pillar_category(self, category_id): + """ + Get the last parent category with type 'pillar' in the chain of categories. + + :param category_id: The initial category for which to find the last 'pillar' parent. + :return: The last 'pillar' parent category or None if not found. + """ + if category_id.type == 'pillar': + return category_id + + while category_id.parent_id: + category_id = category_id.parent_id + if category_id.type == 'pillar': + return category_id + return None + + def action_compare_with_partners_targets(self): + return self.env['ir.actions.act_window']._for_xml_id('kpi_scorecard_odex.scorecard_line_tree_action') + + @api.depends('kpi_id', 'kpi_id.category_id') + def _compute_parent_category(self): + for line in self: + last_pillar_categ = line.get_pillar_category(line.category_id) + last_strategic_categ = line.get_strategic_category(line.category_id) + line.pillar_categ_id = last_pillar_categ.id if last_strategic_categ else False + line.strategic_category_id = last_strategic_categ.id if last_strategic_categ else False + + @api.depends('target_value', 'actual_value', 'weight') + def _compute_progress_kpi(self): + for kpi in self: + if (kpi.target_value > 0.0): + if kpi.actual_value > kpi.target_value: + kpi.progress = 100 + else: + kpi.progress = round(100.0 * kpi.actual_value / kpi.target_value, 2) + else: + kpi.progress = 0.0 + + kpi.weight_progress = round((kpi.progress * kpi.weight) / 100.0, 2) + kpi.plan_progress = kpi.progress * kpi.weight + + def _get_xls_table(self): + """ + The method to prepare dict of values for xls row + + Args: + * spaces - str - to add at the beginning of the name + + Methods: + * _return_xls_formatting - of kpi.item + + Returns: + * dict + """ + result = {} + row = 2 + previous_kpis = {} + for line in self: + parent_id = line.kpi_id.parent_id.id + level = previous_kpis.get(parent_id) is not None and previous_kpis.get(parent_id) + 1 or 0 + previous_kpis.update({line.kpi_id.id: level}) + description = line.description or "" + target_value = line.target_value + planed_value = line.planed_value + actual_value = line.actual_value + overall_style = { + "color": line.result == "success" and "black" or line.result == "failure" and "red" or "orange" + } + if line.computation_error: + target_value = 0 + planed_value = 0 + actual_value = 0 + description = "{} {}".format(line.computation_error, description) + overall_style.update({"color": "orange"}) + planed_value = line.kpi_id._return_xls_formatting(line.planed_value, False) + target_value = line.kpi_id._return_xls_formatting(line.target_value, False) + actual_value = line.kpi_id._return_xls_formatting(line.actual_value, True) + num_style = overall_style.copy() + num_style.update({ + "align": "center", + }) + num_style1 = num_style.copy() + + if line.kpi_id.result_appearance == "percentage": + num_style.update({"num_format": 10}), + overall_style.update({ + "valign": "vjustify", + }) + + result.update({ + "A{}".format(row): {"value": line.kpi_id.code, "style": overall_style, "level": level}, + "B{}".format(row): {"value": line.kpi_id.name, "style": overall_style, "level": level}, + "C{}".format(row): {"value": planed_value, "style": num_style}, + "D{}".format(row): {"value": target_value, "style": num_style}, + "E{}".format(row): {"value": actual_value, "style": num_style}, + "F{}".format(row): {"value": line.progress, "style": num_style1}, + "G{}".format(row): {"value": line.kpi_id.weight, "style": num_style1}, + "H{}".format(row): {"value": line.weight_progress, "style": num_style1}, + "I{}".format(row): {"value": description, "style": overall_style}, + }) + row += 1 + return result + + def action_assign_target_values(self): + self.ensure_one() + partner_target_ids = self.env['partner.target'].search([('kbi_line_id', '=', self.id)]) + action = { + 'name': _('Targets'), + 'type': 'ir.actions.act_window', + 'res_model': 'partner.target', + 'view_mode': 'tree', + 'context': {'default_kbi_line_id': self.id}, + 'target': 'current', + 'domain': [('id', 'in', partner_target_ids.ids)], + } + return action diff --git a/odex25_project/kpi_scorecard_odex/models/partner_target.py b/odex25_project/kpi_scorecard_odex/models/partner_target.py new file mode 100644 index 000000000..76128fc2a --- /dev/null +++ b/odex25_project/kpi_scorecard_odex/models/partner_target.py @@ -0,0 +1,11 @@ +from odoo import fields, models, api + + +class PartnerTarget(models.Model): + _name = 'partner.target' + kbi_line_id = fields.Many2one(comodel_name='kpi.scorecard.line') + partner_id = fields.Many2one(comodel_name='res.partner') + planned_value = fields.Float() + target_value=fields.Float(related='kbi_line_id.target_value') + actual_value=fields.Float(related='kbi_line_id.actual_value') + diff --git a/odex25_project/kpi_scorecard_odex/reports/__init__.py b/odex25_project/kpi_scorecard_odex/reports/__init__.py new file mode 100644 index 000000000..7c68785e9 --- /dev/null +++ b/odex25_project/kpi_scorecard_odex/reports/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- \ No newline at end of file diff --git a/odex25_project/kpi_scorecard_odex/security/ir.model.access.csv b/odex25_project/kpi_scorecard_odex/security/ir.model.access.csv new file mode 100644 index 000000000..402c9b60c --- /dev/null +++ b/odex25_project/kpi_scorecard_odex/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_partner_target,access.partner.target,model_partner_target,,1,1,1,1 diff --git a/odex25_project/kpi_scorecard_odex/views/kpi_category.xml b/odex25_project/kpi_scorecard_odex/views/kpi_category.xml new file mode 100644 index 000000000..d40e1cd8c --- /dev/null +++ b/odex25_project/kpi_scorecard_odex/views/kpi_category.xml @@ -0,0 +1,38 @@ + + + + + + kpi.category.form.inherit + kpi.category + + + + + + + + + + + + kpi.category.tree.inherit + kpi.category + + + + + + + + + + + + + + + + + + diff --git a/odex25_project/kpi_scorecard_odex/views/kpi_item.xml b/odex25_project/kpi_scorecard_odex/views/kpi_item.xml new file mode 100644 index 000000000..d9bc473f5 --- /dev/null +++ b/odex25_project/kpi_scorecard_odex/views/kpi_item.xml @@ -0,0 +1,253 @@ + + + + + + kpi.item.form.inherit + kpi.item + + + + +
+ +
+

+ +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ +

+ +
+ + + + + + + + + + + + + + + + + + +
+
+
+ + + kpi.scorecard.line.pivot + kpi.scorecard.line + + + + + + + + + + + + + + kanban,pivot + +
diff --git a/odex25_project/kpi_scorecard_odex/views/menu_security_cus.xml b/odex25_project/kpi_scorecard_odex/views/menu_security_cus.xml new file mode 100644 index 000000000..c6c781d94 --- /dev/null +++ b/odex25_project/kpi_scorecard_odex/views/menu_security_cus.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/odex25_project/odex25_helpdesk_sale/__init__.py b/odex25_project/odex25_helpdesk_sale/__init__.py new file mode 100644 index 000000000..cde864bae --- /dev/null +++ b/odex25_project/odex25_helpdesk_sale/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models diff --git a/odex25_project/odex25_helpdesk_sale/__manifest__.py b/odex25_project/odex25_helpdesk_sale/__manifest__.py new file mode 100644 index 000000000..bb2c4ba7b --- /dev/null +++ b/odex25_project/odex25_helpdesk_sale/__manifest__.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +{ + 'name': 'Helpdesk After Sales', + 'category': 'Odex25-Project/Odex25-Project', + 'summary': 'Project, Tasks, After Sales', + 'author': "Expert Co. Ltd.", + 'website': "http://www.exp-sa.com", + 'depends': ['odex25_helpdesk', 'sale_management'], + 'auto_install': True, + 'description': """ +Manage the after sale of the products from helpdesk tickets. + """, + 'data': [ + 'views/odex25_helpdesk_views.xml', + ], + 'demo': ['data/odex25_helpdesk_sale_demo.xml'], +} diff --git a/odex25_project/odex25_helpdesk_sale/data/odex25_helpdesk_sale_demo.xml b/odex25_project/odex25_helpdesk_sale/data/odex25_helpdesk_sale_demo.xml new file mode 100644 index 000000000..4f496f622 --- /dev/null +++ b/odex25_project/odex25_helpdesk_sale/data/odex25_helpdesk_sale_demo.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + 1 + 3645.00 + + + + + + + + + + + + 1 + 14.00 + + + + + + + + + + + + 1 + 12.50 + + + + + + + + + + + + + + diff --git a/odex25_project/odex25_helpdesk_sale/i18n/ar.po b/odex25_project/odex25_helpdesk_sale/i18n/ar.po new file mode 100644 index 000000000..b93406335 --- /dev/null +++ b/odex25_project/odex25_helpdesk_sale/i18n/ar.po @@ -0,0 +1,59 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * odex25_helpdesk_sale +# +# Translators: +# Mustafa Rawi , 2020 +# Osama Ahmaro , 2020 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server saas~13.5+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-09-01 07:39+0000\n" +"PO-Revision-Date: 2020-09-07 08:20+0000\n" +"Last-Translator: Osama Ahmaro , 2020\n" +"Language-Team: Arabic (https://www.transifex.com/odoo/teams/41243/ar/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: ar\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" + +#. module: odex25_helpdesk_sale +#: model:ir.model.fields,field_description:odex25_helpdesk_sale.field_odex25_helpdesk_ticket__commercial_partner_id +msgid "Commercial Entity" +msgstr "الكيان التجاري" + +#. module: odex25_helpdesk_sale +#: model:ir.model.fields,field_description:odex25_helpdesk_sale.field_odex25_helpdesk_ticket__display_name +msgid "Display Name" +msgstr "الاسم المعروض" + +#. module: odex25_helpdesk_sale +#: model:ir.model,name:odex25_helpdesk_sale.model_odex25_helpdesk_ticket +msgid "Helpdesk Ticket" +msgstr "تذكرة مكتب المساعدة" + +#. module: odex25_helpdesk_sale +#: model:ir.model.fields,field_description:odex25_helpdesk_sale.field_odex25_helpdesk_ticket__id +msgid "ID" +msgstr "المُعرف" + +#. module: odex25_helpdesk_sale +#: model:ir.model.fields,field_description:odex25_helpdesk_sale.field_odex25_helpdesk_ticket____last_update +msgid "Last Modified on" +msgstr "آخر تعديل في" + +#. module: odex25_helpdesk_sale +#: model:ir.model.fields,field_description:odex25_helpdesk_sale.field_odex25_helpdesk_ticket__sale_order_id +msgid "Ref. Sales Order" +msgstr "" + +#. module: odex25_helpdesk_sale +#: model:ir.model.fields,help:odex25_helpdesk_sale.field_odex25_helpdesk_ticket__sale_order_id +msgid "" +"Reference of the Sales Order to which this ticket refers. Setting this " +"information aims at easing your After Sales process and only serves " +"indicative purposes." +msgstr "" diff --git a/odex25_project/odex25_helpdesk_sale/models/__init__.py b/odex25_project/odex25_helpdesk_sale/models/__init__.py new file mode 100644 index 000000000..27eb465e7 --- /dev/null +++ b/odex25_project/odex25_helpdesk_sale/models/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import odex25_helpdesk diff --git a/odex25_project/odex25_helpdesk_sale/models/odex25_helpdesk.py b/odex25_project/odex25_helpdesk_sale/models/odex25_helpdesk.py new file mode 100644 index 000000000..66e965b0b --- /dev/null +++ b/odex25_project/odex25_helpdesk_sale/models/odex25_helpdesk.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- + +from odoo import api, fields, models + + +class odex25_helpdeskTicket(models.Model): + _inherit = 'odex25_helpdesk.ticket' + + commercial_partner_id = fields.Many2one(related='partner_id.commercial_partner_id') + sale_order_id = fields.Many2one('sale.order', string='Ref. Sales Order', + domain="""[ + '|', (not commercial_partner_id, '=', 1), ('partner_id', 'child_of', commercial_partner_id or []), + ('company_id', '=', company_id)]""", + groups="sales_team.group_sale_salesman,account.group_account_invoice", + help="Reference of the Sales Order to which this ticket refers. Setting this information aims at easing your After Sales process and only serves indicative purposes.") + + def copy(self, default=None): + if not self.env.user.has_group('sales_team.group_sale_salesman') and not self.env.user.has_group('account.group_account_invoice'): + if default is None: + default = {'sale_order_id': False} + else: + default.update({'sale_order_id': False}) + return super(odex25_helpdeskTicket, self).copy(default=default) diff --git a/odex25_project/odex25_helpdesk_sale/static/description/icon.png b/odex25_project/odex25_helpdesk_sale/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4141f52daab6a780510b5f4e3dd762511add78fa GIT binary patch literal 32929 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 OgtWK + + + odex25_helpdesk.ticket.form.inherit.invoicing + odex25_helpdesk.ticket + + + + + + + + {'always_reload': True} + {'res_partner_search_mode': 'customer'} + + + + + + odex25_helpdesk.ticket.form.quick_create + odex25_helpdesk.ticket + + + + {'always_reload': True} + {'res_partner_search_mode': 'customer'} + + + + + + odex25_helpdesk.ticket.form.inherit.invoicing + odex25_helpdesk.ticket + + + + {"no_create": True} + 0 + + + + + + diff --git a/odex25_project/odex25_helpdesk_timesheet/__init__.py b/odex25_project/odex25_helpdesk_timesheet/__init__.py new file mode 100644 index 000000000..55a65860f --- /dev/null +++ b/odex25_project/odex25_helpdesk_timesheet/__init__.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from . import models +from . import wizard + +from odoo import api, SUPERUSER_ID + + +def _odex25_helpdesk_timesheet_post_init(cr, registry): + env = api.Environment(cr, SUPERUSER_ID, {}) + teams = env['odex25_helpdesk.team'].search([('use_odex25_helpdesk_timesheet', '=', True), ('project_id', '=', False), ('use_odex25_helpdesk_sale_timesheet', '=', False)]) + + for team in teams: + team.project_id = team._create_project(team.name, team.use_odex25_helpdesk_sale_timesheet, {'allow_timesheets': True, 'allow_timesheets': True}) + env['odex25_helpdesk.ticket'].search([('team_id', '=', team.id), ('project_id', '=', False)]).write({'project_id': team.project_id.id}) diff --git a/odex25_project/odex25_helpdesk_timesheet/__manifest__.py b/odex25_project/odex25_helpdesk_timesheet/__manifest__.py new file mode 100644 index 000000000..2d599487b --- /dev/null +++ b/odex25_project/odex25_helpdesk_timesheet/__manifest__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +{ + 'name': 'Helpdesk Timesheet', + 'category': 'Odex25-Project/Odex25-Project', + 'summary': 'Project, Tasks, Timesheet', + 'author': "Expert Co. Ltd.", + 'website': "http://www.exp-sa.com", + 'depends': ['hr_timesheet', 'odex25_timesheet_grid', 'odex25_helpdesk'], + 'description': """ + - Allow to set project for Helpdesk team + - Track timesheet for a task from a ticket + """, + 'data': [ + 'security/ir.model.access.csv', + 'security/odex25_helpdesk_timesheet_security.xml', + 'views/odex25_helpdesk_views.xml', + 'views/project_views.xml', + 'wizard/odex25_helpdesk_ticket_create_timesheet_views.xml', + 'data/odex25_helpdesk_timesheet_data.xml', + ], + 'demo': ['data/odex25_helpdesk_timesheet_demo.xml'], + 'post_init_hook': '_odex25_helpdesk_timesheet_post_init' +} diff --git a/odex25_project/odex25_helpdesk_timesheet/data/odex25_helpdesk_timesheet_data.xml b/odex25_project/odex25_helpdesk_timesheet/data/odex25_helpdesk_timesheet_data.xml new file mode 100644 index 000000000..df6c9dbd6 --- /dev/null +++ b/odex25_project/odex25_helpdesk_timesheet/data/odex25_helpdesk_timesheet_data.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/odex25_project/odex25_helpdesk_timesheet/data/odex25_helpdesk_timesheet_demo.xml b/odex25_project/odex25_helpdesk_timesheet/data/odex25_helpdesk_timesheet_demo.xml new file mode 100644 index 000000000..6bfec5c17 --- /dev/null +++ b/odex25_project/odex25_helpdesk_timesheet/data/odex25_helpdesk_timesheet_demo.xml @@ -0,0 +1,25 @@ + + + + + + + + + Fix Drawer Slides + + + 01.00 + + + + + Changed Drawer Handle + + + 0.5 + + + + + diff --git a/odex25_project/odex25_helpdesk_timesheet/i18n/ar.po b/odex25_project/odex25_helpdesk_timesheet/i18n/ar.po new file mode 100644 index 000000000..d3814fe02 --- /dev/null +++ b/odex25_project/odex25_helpdesk_timesheet/i18n/ar.po @@ -0,0 +1,404 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * odex25_helpdesk_timesheet +# +# Translators: +# Sherif Abd Ekmoniem , 2020 +# Mustafa Rawi , 2020 +# Akram Alfusayal , 2020 +# amrnegm , 2020 +# Martin Trigaux, 2020 +# Mohammed Ibrahim , 2020 +# Osama Ahmaro , 2020 +# Shaima Safar , 2020 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-11-27 13:48+0000\n" +"PO-Revision-Date: 2020-09-07 08:20+0000\n" +"Last-Translator: Shaima Safar , 2020\n" +"Language-Team: Arabic (https://www.transifex.com/odoo/teams/41243/ar/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: ar\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" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket___related_task_ids +msgid " Related Task" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_project_project__ticket_count +msgid "# Tickets" +msgstr "# التذاكر" + +#. module: odex25_helpdesk_timesheet +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_timer_ticket_view_kanban +msgid "" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_timer_ticket_view_kanban +msgid "" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: code:addons/odex25_helpdesk_timesheet/models/odex25_helpdesk.py:0 +#, python-format +msgid "" +"All timesheet hours will be assigned to the selected task on save. Discard " +"to avoid the change." +msgstr "" +"عند الحفظ، سيتم إسناد ساعات سجل الأنشطة للمهمة المختارة. اختر تجاهل لتفادي " +"تطبيق التغيير." + +#. module: odex25_helpdesk_timesheet +#: model:ir.model,name:odex25_helpdesk_timesheet.model_account_analytic_line +msgid "Analytic Line" +msgstr "البند التحليلي" + +#. module: odex25_helpdesk_timesheet +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_ticket_create_timesheet_view_form +msgid "Cancel" +msgstr "الغاء" + +#. module: odex25_helpdesk_timesheet +#: code:addons/odex25_helpdesk_timesheet/models/odex25_helpdesk.py:0 +#, python-format +msgid "Closed" +msgstr "مغلق" + +#. module: odex25_helpdesk_timesheet +#: code:addons/odex25_helpdesk_timesheet/models/odex25_helpdesk.py:0 +#, python-format +msgid "Confirm Time Spent" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model,name:odex25_helpdesk_timesheet.model_odex25_helpdesk_ticket_create_timesheet +msgid "Create Timesheet from ticket" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket_create_timesheet__create_uid +msgid "Created by" +msgstr "أنشئ بواسطة" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket_create_timesheet__create_date +msgid "Created on" +msgstr "أنشئ في" + +#. module: odex25_helpdesk_timesheet +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_ticket_create_timesheet_view_form +msgid "Describe your activity..." +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket_create_timesheet__description +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_ticket_view_form_inherit_odex25_helpdesk_timesheet +msgid "Description" +msgstr "الوصف" + +#. module: odex25_helpdesk_timesheet +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_ticket_view_form_inherit_odex25_helpdesk_timesheet +msgid "Description of the ticket..." +msgstr "وصف التذكرة..." + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_account_analytic_line__display_name +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_team__display_name +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__display_name +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket_create_timesheet__display_name +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_project_project__display_name +msgid "Display Name" +msgstr "الاسم المعروض" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__display_timer +msgid "Display Timer" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__display_timer_pause +msgid "Display Timer Pause" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__display_timer_resume +msgid "Display Timer Resume" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__display_timer_start_primary +msgid "Display Timer Start Primary" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__display_timer_start_secondary +msgid "Display Timer Start Secondary" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__display_timer_stop +msgid "Display Timer Stop" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__display_timesheet_timer +msgid "Display Timesheet Time" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_team__display_timesheet_timer +msgid "Display Timesheet Timer" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_ticket_create_timesheet_view_form +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_ticket_view_form_inherit_odex25_helpdesk_timesheet +msgid "Duration" +msgstr "المدة" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__encode_uom_in_days +msgid "Encode Uom In Days" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model,name:odex25_helpdesk_timesheet.model_odex25_helpdesk_team +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_project_project__odex25_helpdesk_team +msgid "Helpdesk Team" +msgstr "فريق مكتب المساعدة" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model,name:odex25_helpdesk_timesheet.model_odex25_helpdesk_ticket +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_account_analytic_line__odex25_helpdesk_ticket_id +msgid "Helpdesk Ticket" +msgstr "تذكرة مكتب المساعدة" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_account_analytic_line__id +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_team__id +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__id +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket_create_timesheet__id +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_project_project__id +msgid "ID" +msgstr "المُعرف" + +#. module: odex25_helpdesk_timesheet +#: code:addons/odex25_helpdesk_timesheet/models/odex25_helpdesk.py:0 +#, python-format +msgid "In Progress" +msgstr "قيد التنفيذ" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__is_closed +msgid "Is Closed" +msgstr "مقفل" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__is_task_active +msgid "Is Task Active" +msgstr "هل المهمة نشطة" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__is_timer_running +msgid "Is Timer Running" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_account_analytic_line____last_update +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_team____last_update +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket____last_update +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket_create_timesheet____last_update +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_project_project____last_update +msgid "Last Modified on" +msgstr "آخر تعديل في" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket_create_timesheet__write_uid +msgid "Last Updated by" +msgstr "آخر تحديث بواسطة" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket_create_timesheet__write_date +msgid "Last Updated on" +msgstr "آخر تحديث في" + +#. module: odex25_helpdesk_timesheet +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_ticket_view_form_inherit_odex25_helpdesk_timesheet +msgid "Pause" +msgstr "إيقاف" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model,name:odex25_helpdesk_timesheet.model_project_project +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_team__project_id +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__project_id +msgid "Project" +msgstr "المشروع" + +#. module: odex25_helpdesk_timesheet +#: model:ir.actions.act_window,name:odex25_helpdesk_timesheet.project_project_action_view_odex25_helpdesk_tickets +msgid "Project Tickets" +msgstr "تذاكر المشروع" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,help:odex25_helpdesk_timesheet.field_odex25_helpdesk_team__project_id +msgid "" +"Project to which the tickets (and the timesheets) will be linked by default." +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_ticket_view_form_inherit_odex25_helpdesk_timesheet +msgid "Resume" +msgstr "استكمال الجلسة" + +#. module: odex25_helpdesk_timesheet +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_ticket_create_timesheet_view_form +msgid "Save" +msgstr "حفظ" + +#. module: odex25_helpdesk_timesheet +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_ticket_create_timesheet_view_form +msgid "Save time" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_ticket_view_form_inherit_odex25_helpdesk_timesheet +msgid "Start" +msgstr "بدء" + +#. module: odex25_helpdesk_timesheet +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_ticket_view_form_inherit_odex25_helpdesk_timesheet +msgid "Stop" +msgstr "إيقاف" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__task_id +msgid "Task" +msgstr "المهمة" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,help:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__is_closed +msgid "Tasks in this stage are considered as closed." +msgstr "المهام في هذه المرحلة تعتبر مغلقة." + +#. module: odex25_helpdesk_timesheet +#: code:addons/odex25_helpdesk_timesheet/models/odex25_helpdesk.py:0 +#, python-format +msgid "The project is required to track time on ticket." +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: code:addons/odex25_helpdesk_timesheet/models/odex25_helpdesk.py:0 +#, python-format +msgid "The task must be in ticket's project." +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,help:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__task_id +msgid "The task must have the same customer as this ticket." +msgstr "يجب أن يكون العميل المرتبط بالمهمة هو نفسه العميل صاحب التذكرة." + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.constraint,message:odex25_helpdesk_timesheet.constraint_odex25_helpdesk_ticket_create_timesheet_time_positive +msgid "The timesheet's time must be positive" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,help:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__use_odex25_helpdesk_timesheet +msgid "This required to have project module installed." +msgstr "يتطلب هذا تثبيت موديول المشروع." + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket_create_timesheet__ticket_id +msgid "Ticket" +msgstr "التذكرة" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,help:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket_create_timesheet__ticket_id +msgid "Ticket for which we are creating a sales order" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_project_project__ticket_ids +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.project_project_view_form_inherit_odex25_helpdesk_timesheet +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.project_project_view_project_tickets_kanban_inherited +msgid "Tickets" +msgstr "تذاكر" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket_create_timesheet__time_spent +msgid "Time" +msgstr "الوقت" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__timer_pause +msgid "Timer Last Pause" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__timer_start +msgid "Timer Start" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_ticket_view_form_inherit_odex25_helpdesk_timesheet +msgid "Timesheet Activities" +msgstr "أنشطة سجل النشاط" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_team__timesheet_timer +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__timesheet_timer +msgid "Timesheet Timer" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__use_odex25_helpdesk_timesheet +msgid "Timesheet activated on Team" +msgstr "سجل النشاط المُفعل للفريق" + +#. module: odex25_helpdesk_timesheet +#: code:addons/odex25_helpdesk_timesheet/models/odex25_helpdesk.py:0 +#, python-format +msgid "" +"Timesheet hours will not be assigned to a customer task. Set a task to " +"charge a customer." +msgstr "لن يتم إسناد ساعات سجل الأنشطة لمهمة عميل. اختر مهمة لتُحسب على عميل." + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__timesheet_ids +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_ticket_view_form_inherit_odex25_helpdesk_timesheet +msgid "Timesheets" +msgstr "سجلات الأنشطة" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__total_hours_spent +msgid "Total Hours Spent" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_ticket_view_form_inherit_odex25_helpdesk_timesheet +msgid "Total hours" +msgstr "إجمالي الساعات" + +#. module: odex25_helpdesk_timesheet +#: model_terms:ir.ui.view,arch_db:odex25_helpdesk_timesheet.odex25_helpdesk_team_view_form_inherit_odex25_helpdesk_timesheet +msgid "Track your time using a timer" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: model:ir.model.fields,field_description:odex25_helpdesk_timesheet.field_odex25_helpdesk_ticket__user_timer_id +msgid "User Timer" +msgstr "" + +#. module: odex25_helpdesk_timesheet +#: code:addons/odex25_helpdesk_timesheet/models/odex25_helpdesk.py:0 +#, python-format +msgid "Warning" +msgstr "تحذير" diff --git a/odex25_project/odex25_helpdesk_timesheet/models/__init__.py b/odex25_project/odex25_helpdesk_timesheet/models/__init__.py new file mode 100644 index 000000000..19e731b0b --- /dev/null +++ b/odex25_project/odex25_helpdesk_timesheet/models/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + +from . import analytic +from . import odex25_helpdesk +from . import project diff --git a/odex25_project/odex25_helpdesk_timesheet/models/analytic.py b/odex25_project/odex25_helpdesk_timesheet/models/analytic.py new file mode 100644 index 000000000..730bfa04a --- /dev/null +++ b/odex25_project/odex25_helpdesk_timesheet/models/analytic.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- + +from odoo import api, fields, models +from odoo.osv import expression + + +class AccountAnalyticLine(models.Model): + _inherit = 'account.analytic.line' + + odex25_helpdesk_ticket_id = fields.Many2one('odex25_helpdesk.ticket', 'Helpdesk Ticket') + + def _compute_task_id(self): + super(AccountAnalyticLine, self)._compute_task_id() + for line in self.filtered(lambda line: line.odex25_helpdesk_ticket_id): + line.task_id = line.odex25_helpdesk_ticket_id.task_id + + def _timesheet_preprocess(self, vals): + odex25_helpdesk_ticket_id = vals.get('odex25_helpdesk_ticket_id') + if odex25_helpdesk_ticket_id: + ticket = self.env['odex25_helpdesk.ticket'].browse(odex25_helpdesk_ticket_id) + if ticket.project_id: + vals['project_id'] = ticket.project_id.id + if ticket.task_id: + vals['task_id'] = ticket.task_id.id + vals = super(AccountAnalyticLine, self)._timesheet_preprocess(vals) + return vals + + def _timesheet_get_portal_domain(self): + domain = super(AccountAnalyticLine, self)._timesheet_get_portal_domain() + return expression.OR([domain, self._timesheet_in_odex25_helpdesk_get_portal_domain()]) + + def _timesheet_in_odex25_helpdesk_get_portal_domain(self): + return [ + '&', + '&', + '&', + ('task_id', '=', False), + ('odex25_helpdesk_ticket_id', '!=', False), + '|', + '|', + ('project_id.message_partner_ids', 'child_of', [self.env.user.partner_id.commercial_partner_id.id]), + ('project_id.allowed_portal_user_ids', 'child_of', [self.env.user.id]), + ('odex25_helpdesk_ticket_id.message_partner_ids', 'child_of', [self.env.user.partner_id.commercial_partner_id.id]), + ('project_id.privacy_visibility', '=', 'portal') + ] diff --git a/odex25_project/odex25_helpdesk_timesheet/models/odex25_helpdesk.py b/odex25_project/odex25_helpdesk_timesheet/models/odex25_helpdesk.py new file mode 100644 index 000000000..827a00f90 --- /dev/null +++ b/odex25_project/odex25_helpdesk_timesheet/models/odex25_helpdesk.py @@ -0,0 +1,253 @@ +# -*- coding: utf-8 -*- +from math import ceil + +from odoo import api, fields, models, _ +from odoo.exceptions import ValidationError + + +class odex25_helpdeskTeam(models.Model): + _inherit = 'odex25_helpdesk.team' + + project_id = fields.Many2one("project.project", string="Project", ondelete="restrict", domain="[('allow_timesheets', '=', True), ('company_id', '=', company_id)]", + help="Project to which the tickets (and the timesheets) will be linked by default.") + timesheet_timer = fields.Boolean('Timesheet Timer', default=True) + display_timesheet_timer = fields.Boolean(compute='_compute_display_timesheet_timer') + + @api.depends('use_odex25_helpdesk_timesheet') + def _compute_display_timesheet_timer(self): + is_uom_hour = self.env.company.timesheet_encode_uom_id == self.env.ref('uom.product_uom_hour') + for team in self: + team.display_timesheet_timer = team.use_odex25_helpdesk_timesheet and is_uom_hour + + @api.depends('use_odex25_helpdesk_timesheet') + def _compute_timesheet_timer(self): + for team in self: + team.timesheet_timer = team.use_odex25_helpdesk_timesheet + + def _create_project(self, name, allow_billable, other): + return self.env['project.project'].create({ + 'name': name, + 'type_ids': [ + (0, 0, {'name': _('In Progress')}), + (0, 0, {'name': _('Closed'), 'is_closed': True}) + ], + 'allow_timesheets': True, + 'allow_timesheet_timer': True, + **other, + }) + + @api.model + def create(self, vals): + if vals.get('use_odex25_helpdesk_timesheet') and not vals.get('project_id'): + allow_billable = vals.get('use_odex25_helpdesk_sale_timesheet') + vals['project_id'] = self._create_project(vals['name'], allow_billable, {}).id + return super(odex25_helpdeskTeam, self).create(vals) + + def write(self, vals): + if 'use_odex25_helpdesk_timesheet' in vals and not vals['use_odex25_helpdesk_timesheet']: + vals['project_id'] = False + result = super(odex25_helpdeskTeam, self).write(vals) + for team in self.filtered(lambda team: team.use_odex25_helpdesk_timesheet and not team.project_id): + team.project_id = team._create_project(team.name, team.use_odex25_helpdesk_sale_timesheet, {'allow_timesheets': True, 'allow_timesheet_timer': True}) + self.env['odex25_helpdesk.ticket'].search([('team_id', '=', team.id), ('project_id', '=', False)]).write({'project_id': team.project_id.id}) + return result + + @api.model + def _init_data_create_project(self): + # TODO: remove me in master + return + + +class odex25_helpdeskTicket(models.Model): + _inherit = 'odex25_helpdesk.ticket' + # _inherit = ['odex25_helpdesk.ticket', 'timer.mixin'] + + @api.model + def default_get(self, fields_list): + result = super(odex25_helpdeskTicket, self).default_get(fields_list) + if 'project_id' in fields_list and result.get('team_id') and not result.get('project_id'): + result['project_id'] = self.env['odex25_helpdesk.team'].browse(result['team_id']).project_id.id + return result + + # TODO: [XBO] change this field in related and stored (to count the number of tickets per project) field to the one in odex25_helpdesk.team + project_id = fields.Many2one("project.project", string="Project", domain="[('allow_timesheets', '=', True), ('company_id', '=', company_id)]") + # TODO: [XBO] remove me in master + task_id = fields.Many2one( + "project.task", string="Task", compute='_compute_task_id', store=True, readonly=False, + domain="[('id', 'in', _related_task_ids)]", tracking=True, + help="The task must have the same customer as this ticket.") + # TODO: [XBO] remove me in master (since task_id field will be removed too) + _related_task_ids = fields.Many2many('project.task', compute='_compute_related_task_ids') + timesheet_ids = fields.One2many('account.analytic.line', 'odex25_helpdesk_ticket_id', 'Timesheets') + is_closed = fields.Boolean(related="task_id.stage_id.is_closed", string="Is Closed", readonly=True) + # TODO: [XBO] remove me in master (since task_id field will be removed too) + is_task_active = fields.Boolean(related="task_id.active", string='Is Task Active', readonly=True) + use_odex25_helpdesk_timesheet = fields.Boolean('Timesheet activated on Team', related='team_id.use_odex25_helpdesk_timesheet', readonly=True) + timesheet_timer = fields.Boolean(related='team_id.timesheet_timer') + display_timesheet_timer = fields.Boolean("Display Timesheet Time", compute='_compute_display_timesheet_timer') + total_hours_spent = fields.Float(compute='_compute_total_hours_spent', default=0) + display_timer_start_secondary = fields.Boolean(compute='_compute_display_timer_buttons') + display_timer = fields.Boolean(compute='_compute_display_timer') + encode_uom_in_days = fields.Boolean(compute='_compute_encode_uom_in_days') + + def _compute_encode_uom_in_days(self): + self.encode_uom_in_days = self.env.company.timesheet_encode_uom_id == self.env.ref('uom.product_uom_day') + + @api.depends('display_timesheet_timer', 'timer_start', 'timer_pause', 'total_hours_spent') + def _compute_display_timer_buttons(self): + for ticket in self: + if not ticket.display_timesheet_timer: + ticket.update({ + 'display_timer_start_primary': False, + 'display_timer_start_secondary': False, + 'display_timer_stop': False, + 'display_timer_pause': False, + 'display_timer_resume': False, + }) + else: + super(odex25_helpdeskTicket, ticket)._compute_display_timer_buttons() + ticket.display_timer_start_secondary = ticket.display_timer_start_primary + if not ticket.timer_start: + ticket.update({ + 'display_timer_stop': False, + 'display_timer_pause': False, + 'display_timer_resume': False, + }) + if not ticket.total_hours_spent: + ticket.display_timer_start_secondary = False + else: + ticket.display_timer_start_primary = False + + def _compute_display_timer(self): + if self.env.user.has_group('odex25_helpdesk.group_odex25_helpdesk_user') and self.env.user.has_group('hr_timesheet.group_hr_timesheet_user'): + self.display_timer = True + else: + self.display_timer = False + + @api.depends('use_odex25_helpdesk_timesheet', 'timesheet_timer', 'timesheet_ids', 'encode_uom_in_days') + def _compute_display_timesheet_timer(self): + for ticket in self: + ticket.display_timesheet_timer = ticket.use_odex25_helpdesk_timesheet and ticket.timesheet_timer and not ticket.encode_uom_in_days + + @api.depends('project_id', 'company_id') + def _compute_related_task_ids(self): + # TODO: [XBO] remove me in master because the task_id will be removed, then this compute and the _related_task_ids field will be useless + for t in self: + domain = [('project_id.allow_timesheets', '=', True), ('company_id', '=', t.company_id.id)] + if t.project_id: + domain = [('project_id', '=', t.project_id.id)] + t._related_task_ids = self.env['project.task'].search(domain)._origin + + @api.depends('timesheet_ids') + def _compute_total_hours_spent(self): + for ticket in self: + ticket.total_hours_spent = round(sum(ticket.timesheet_ids.mapped('unit_amount')), 2) + + @api.depends('project_id') + def _compute_task_id(self): + # TODO: [XBO] remove me in master (task_id field will be removed) + with_different_project = self.filtered(lambda t: t.project_id != t.task_id.project_id) + with_different_project.update({'task_id': False}) + + @api.onchange('task_id') + def _onchange_task_id(self): + # TODO: remove me in master + return + + @api.constrains('project_id', 'team_id') + def _check_project_id(self): + # TODO: [XBO] see in master if we must remove this method, but since project_id will be a related field, this constrains will be useless. + for ticket in self: + if ticket.use_odex25_helpdesk_timesheet and not ticket.project_id: + raise ValidationError(_("The project is required to track time on ticket.")) + + @api.constrains('project_id', 'task_id') + def _check_task_in_project(self): + # TODO: [XBO] remove me in master (task_id field will be removed in master) + for ticket in self: + if ticket.task_id: + if ticket.task_id.project_id != ticket.project_id: + raise ValidationError(_("The task must be in ticket's project.")) + + def _get_timesheet(self): + # return not invoiced timesheet + timesheet_ids = self.timesheet_ids + return timesheet_ids.filtered(lambda t: (not t.timesheet_invoice_id or t.timesheet_invoice_id.state == 'cancel')) + + @api.model_create_multi + def create(self, value_list): + team_ids = set([value['team_id'] for value in value_list if value.get('team_id')]) + teams = self.env['odex25_helpdesk.team'].browse(team_ids) + + team_project_map = {} # map with the team that require a project + for team in teams: + if team.use_odex25_helpdesk_timesheet: + team_project_map[team.id] = team.project_id.id + + for value in value_list: + if value.get('team_id') and not value.get('project_id') and team_project_map.get(value['team_id']): + value['project_id'] = team_project_map[value['team_id']] + + return super(odex25_helpdeskTicket, self).create(value_list) + + def write(self, values): + result = super(odex25_helpdeskTicket, self).write(values) + # force timesheet values: changing ticket's task or project will reset timesheet ones + timesheet_vals = {} + for fname in self._timesheet_forced_fields(): + if fname in values: + timesheet_vals[fname] = values[fname] + if timesheet_vals: + for timesheet in self.sudo()._get_timesheet(): + timesheet.write(timesheet_vals) # sudo since Helpdesk user can change task + return result + +# @api.model +# def _fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): +# """ Set the correct label for `unit_amount`, depending on company UoM """ +# result = super(odex25_helpdeskTicket, self)._fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu) +# result['arch'] = self.env['account.analytic.line']._apply_timesheet_label(result['arch']) +# return result + + def action_view_ticket_task(self): + # TODO: [XBO] remove me in master (task_id field will be removed in master) + self.ensure_one() + return { + 'view_mode': 'form', + 'res_model': 'project.task', + 'type': 'ir.actions.act_window', + 'res_id': self.task_id.id, + } + + def _timesheet_forced_fields(self): + """ return the list of field that should also be written on related timesheets """ + return ['task_id', 'project_id'] + + def action_timer_start(self): + if not self.user_timer_id.timer_start and self.display_timesheet_timer: + super().action_timer_start() + + def action_timer_stop(self): + # timer was either running or paused + if self.user_timer_id.timer_start and self.display_timesheet_timer: + minutes_spent = self.user_timer_id._get_minutes_spent() + minimum_duration = int(self.env['ir.config_parameter'].sudo().get_param('hr_timesheet.timesheet_min_duration', 0)) + rounding = int(self.env['ir.config_parameter'].sudo().get_param('hr_timesheet.timesheet_rounding', 0)) + minutes_spent = self._timer_rounding(minutes_spent, minimum_duration, rounding) + return self._action_open_new_timesheet(minutes_spent * 60 / 3600) + return False + + def _action_open_new_timesheet(self, time_spent): + return { + "name": _("Confirm Time Spent"), + "type": 'ir.actions.act_window', + "res_model": 'odex25_helpdesk.ticket.create.timesheet', + "views": [[False, "form"]], + "target": 'new', + "context": { + **self.env.context, + 'active_id': self.id, + 'active_model': self._name, + 'default_time_spent': time_spent, + }, + } diff --git a/odex25_project/odex25_helpdesk_timesheet/models/project.py b/odex25_project/odex25_helpdesk_timesheet/models/project.py new file mode 100644 index 000000000..6b7b58de3 --- /dev/null +++ b/odex25_project/odex25_helpdesk_timesheet/models/project.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- + +from odoo import api, fields, models + +class Project(models.Model): + _inherit = 'project.project' + + ticket_ids = fields.One2many('odex25_helpdesk.ticket', 'project_id', string='Tickets') + ticket_count = fields.Integer('# Tickets', compute='_compute_ticket_count') + + odex25_helpdesk_team = fields.One2many('odex25_helpdesk.team', 'project_id') + + @api.depends('ticket_ids.project_id') + def _compute_ticket_count(self): + if not self.user_has_groups('odex25_helpdesk.group_odex25_helpdesk_user'): + self.ticket_count = 0 + return + result = self.env['odex25_helpdesk.ticket'].read_group([ + ('project_id', 'in', self.ids) + ], ['project_id'], ['project_id']) + data = {data['project_id'][0]: data['project_id_count'] for data in result} + for project in self: + project.ticket_count = data.get(project.id, 0) + + @api.depends('odex25_helpdesk_team.timesheet_timer') + def _compute_allow_timesheet_timer(self): + super(Project, self)._compute_allow_timesheet_timer() + + for project in self: + project.allow_timesheet_timer = project.allow_timesheet_timer or project.odex25_helpdesk_team.timesheet_timer diff --git a/odex25_project/odex25_helpdesk_timesheet/security/ir.model.access.csv b/odex25_project/odex25_helpdesk_timesheet/security/ir.model.access.csv new file mode 100644 index 000000000..4a3d31c32 --- /dev/null +++ b/odex25_project/odex25_helpdesk_timesheet/security/ir.model.access.csv @@ -0,0 +1,6 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_project_project_odex25_helpdesk_user,project.project.odex25_helpdesk.user,project.model_project_project,odex25_helpdesk.group_odex25_helpdesk_user,1,0,0,0 +access_project_task_odex25_helpdesk_user,project.task.odex25_helpdesk.user,project.model_project_task,odex25_helpdesk.group_odex25_helpdesk_user,1,0,0,0 +access_analytic_account_heldpdesk_user,analytic.account.odex25_helpdesk.user,analytic.model_account_analytic_account,odex25_helpdesk.group_odex25_helpdesk_user,1,1,0,0 +access_analytic_line_heldpdesk_user,analytic.line.odex25_helpdesk.user,analytic.model_account_analytic_line,odex25_helpdesk.group_odex25_helpdesk_user,1,1,1,1 +access_odex25_helpdesk_ticket_create_timesheet,access.odex25_helpdesk.ticket.create.timesheet,model_odex25_helpdesk_ticket_create_timesheet,odex25_helpdesk.group_odex25_helpdesk_user,1,1,1,0 diff --git a/odex25_project/odex25_helpdesk_timesheet/security/odex25_helpdesk_timesheet_security.xml b/odex25_project/odex25_helpdesk_timesheet/security/odex25_helpdesk_timesheet_security.xml new file mode 100644 index 000000000..29233bfed --- /dev/null +++ b/odex25_project/odex25_helpdesk_timesheet/security/odex25_helpdesk_timesheet_security.xml @@ -0,0 +1,26 @@ + + + + + account.analytic.line.odex25_helpdesk.user + + [('user_id', '=', user.id), ('odex25_helpdesk_ticket_id', '!=', False)] + + + + + + + + + account.analytic.line.timesheet.manager + + [('odex25_helpdesk_ticket_id', '!=', False)] + + + + + + + + \ No newline at end of file diff --git a/odex25_project/odex25_helpdesk_timesheet/static/description/icon.png b/odex25_project/odex25_helpdesk_timesheet/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4141f52daab6a780510b5f4e3dd762511add78fa GIT binary patch literal 32929 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 OgtWK + + + + odex25_helpdesk.team.form.inherit.timesheet + odex25_helpdesk.team + + + +
+
+
+ + +
+
+ +
+
+
+
+
+
+
+ + + odex25_helpdesk.ticket.form.inherit.timesheet + odex25_helpdesk.ticket + + + + + ml-2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+ +
+
+
+
+ +
+
+ + + +
+
+
+
+
+
+
+ + + + + + + + + + + +
+
+ + + + + + + +
+
+
+
+
+ + + odex25_helpdesk.ticket.search.inherit.timesheet + odex25_helpdesk.ticket + + + + + + + + + + + odex25_helpdesk.ticket.kanban.timer + odex25_helpdesk.ticket + 5 + + + + + + + + + + + + + + + +
diff --git a/odex25_project/odex25_helpdesk_timesheet/views/project_views.xml b/odex25_project/odex25_helpdesk_timesheet/views/project_views.xml new file mode 100644 index 000000000..15d3024a1 --- /dev/null +++ b/odex25_project/odex25_helpdesk_timesheet/views/project_views.xml @@ -0,0 +1,47 @@ + + + + + Project Tickets + odex25_helpdesk.ticket + kanban,tree,form,pivot,graph + + {'search_default_project_id': active_id, 'default_project_id': active_id} + + + + project.project.tickets.kanban.inherited + project.project + + 24 + + + + + + + + + + + + project.form.inherit.odex25_helpdesk.timesheet + project.project + + +
+ +
+
+ +
+ +
diff --git a/odex25_project/odex25_helpdesk_timesheet/wizard/__init__.py b/odex25_project/odex25_helpdesk_timesheet/wizard/__init__.py new file mode 100644 index 000000000..2ba46a4a2 --- /dev/null +++ b/odex25_project/odex25_helpdesk_timesheet/wizard/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import odex25_helpdesk_ticket_create_timesheet diff --git a/odex25_project/odex25_helpdesk_timesheet/wizard/odex25_helpdesk_ticket_create_timesheet.py b/odex25_project/odex25_helpdesk_timesheet/wizard/odex25_helpdesk_ticket_create_timesheet.py new file mode 100644 index 000000000..aff87ba79 --- /dev/null +++ b/odex25_project/odex25_helpdesk_timesheet/wizard/odex25_helpdesk_ticket_create_timesheet.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- + +from odoo import api, fields, models + + +class odex25_helpdeskTicketCreateTimesheet(models.TransientModel): + _name = 'odex25_helpdesk.ticket.create.timesheet' + _description = "Create Timesheet from ticket" + + _sql_constraints = [('time_positive', 'CHECK(time_spent > 0)', "The timesheet's time must be positive" )] + + time_spent = fields.Float('Time', digits=(16, 2)) + description = fields.Char('Description') + ticket_id = fields.Many2one( + 'odex25_helpdesk.ticket', "Ticket", required=True, + default=lambda self: self.env.context.get('active_id', None), + help="Ticket for which we are creating a sales order", + ) + + def action_generate_timesheet(self): + values = { + 'task_id': self.ticket_id.task_id.id, + 'project_id': self.ticket_id.project_id.id, + 'date': fields.Datetime.now(), + 'name': self.description, + 'user_id': self.env.uid, + 'unit_amount': self.time_spent, + } + + timesheet = self.env['account.analytic.line'].create(values) + + self.ticket_id.write({ + 'timer_start': False, + 'timer_pause': False + }) + self.ticket_id.timesheet_ids = [(4, timesheet.id, None)] + self.ticket_id.user_timer_id.unlink() + return timesheet diff --git a/odex25_project/odex25_helpdesk_timesheet/wizard/odex25_helpdesk_ticket_create_timesheet_views.xml b/odex25_project/odex25_helpdesk_timesheet/wizard/odex25_helpdesk_ticket_create_timesheet_views.xml new file mode 100644 index 000000000..c4738a0a7 --- /dev/null +++ b/odex25_project/odex25_helpdesk_timesheet/wizard/odex25_helpdesk_ticket_create_timesheet_views.xml @@ -0,0 +1,22 @@ + + + + + odex25_helpdesk.ticket.create.timesheet.wizard.form + odex25_helpdesk.ticket.create.timesheet + +
+ + + + + +
+
+
+
+
+ +
diff --git a/odex25_project/project_base/.idea/inspectionProfiles/profiles_settings.xml b/odex25_project/project_base/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 000000000..105ce2da2 --- /dev/null +++ b/odex25_project/project_base/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/odex25_project/project_base/.idea/misc.xml b/odex25_project/project_base/.idea/misc.xml new file mode 100644 index 000000000..2d83d70ff --- /dev/null +++ b/odex25_project/project_base/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/odex25_project/project_base/.idea/modules.xml b/odex25_project/project_base/.idea/modules.xml new file mode 100644 index 000000000..d6d1f7c82 --- /dev/null +++ b/odex25_project/project_base/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/odex25_project/project_base/.idea/project_base.iml b/odex25_project/project_base/.idea/project_base.iml new file mode 100644 index 000000000..d0876a78d --- /dev/null +++ b/odex25_project/project_base/.idea/project_base.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/odex25_project/project_base/.idea/workspace.xml b/odex25_project/project_base/.idea/workspace.xml new file mode 100644 index 000000000..33a513015 --- /dev/null +++ b/odex25_project/project_base/.idea/workspace.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + 1715529731411 + + + + \ No newline at end of file diff --git a/odex25_project/project_base/__init__.py b/odex25_project/project_base/__init__.py new file mode 100644 index 000000000..f2155f77c --- /dev/null +++ b/odex25_project/project_base/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +from . import models +from . import wizard + diff --git a/odex25_project/project_base/__manifest__.py b/odex25_project/project_base/__manifest__.py new file mode 100644 index 000000000..549eabee9 --- /dev/null +++ b/odex25_project/project_base/__manifest__.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Odex25 Project Base", + 'summary': """Odex25 Project Base""", + 'description': """ +1- Project Charter +2- Project Stage +3- Project Tasks +4- Project Invoice Requests + """, + 'category': 'Odex25-Project/Odex25-Project', + 'version': '1.0', + 'depends': ['sale_timesheet','hr' ,'project','mail', 'portal', 'base' ,'account'], + 'data': [ + 'data/project_data.xml', + 'data/project_cron.xml', + 'security/project_security.xml', + 'security/ir_rule_allow_users.xml', + 'security/ir.model.access.csv', + 'wizard/project_hold_reason_view.xml', + 'wizard/edit_project_phase_view.xml', + 'wizard/down_payment_invoice_advance_views.xml', + 'report/project_reports.xml', + 'report/project_report_templates.xml', + 'report/project_invoice_report_templates.xml', + 'views/project_views.xml', + 'views/project_invoice_views.xml', + 'views/project_phase_view.xml', + 'views/res_config_setting.xml', + 'views/project_task_views.xml', + 'views/asset.xml', + + ], +} diff --git a/odex25_project/project_base/data/project_cron.xml b/odex25_project/project_base/data/project_cron.xml new file mode 100644 index 000000000..1715fd934 --- /dev/null +++ b/odex25_project/project_base/data/project_cron.xml @@ -0,0 +1,26 @@ + + + + Project: Update Project Status + 1 + days + -1 + + + + model.update_project_status() + code + + + + Project: Send Invoice Issue Notification + 1 + days + -1 + + + + model.project_invoice_notification() + code + + diff --git a/odex25_project/project_base/data/project_data.xml b/odex25_project/project_base/data/project_data.xml new file mode 100644 index 000000000..c2489b81d --- /dev/null +++ b/odex25_project/project_base/data/project_data.xml @@ -0,0 +1,16 @@ + + + + + + Project Number + project.project + P%(y)s- + 5 + + + + + diff --git a/odex25_project/project_base/i18n/ar.po b/odex25_project/project_base/i18n/ar.po new file mode 100644 index 000000000..b4a7497b9 --- /dev/null +++ b/odex25_project/project_base/i18n/ar.po @@ -0,0 +1,48 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * project +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-05-11 15:00+0000\n" +"PO-Revision-Date: 2024-05-11 15:00+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: project +#: model:ir.actions.act_window,name:project.open_view_project_all +#: model:ir.actions.act_window,name:project.open_view_project_all_config +#: model:ir.model.fields,field_description:project.field_account_analytic_account__project_ids +#: model:ir.model.fields,field_description:project.field_project_delete_wizard__project_ids +#: model:ir.model.fields,field_description:project.field_project_task_type__project_ids +#: model:ir.model.fields,field_description:project.field_project_task_type_delete_wizard__project_ids +#: model:ir.ui.menu,name:project.menu_projects +#: model:ir.ui.menu,name:project.menu_projects_config +#: model_terms:ir.ui.view,arch_db:project.account_analytic_account_view_form_inherit +#: model_terms:ir.ui.view,arch_db:project.portal_layout +#: model_terms:ir.ui.view,arch_db:project.portal_my_home +#: model_terms:ir.ui.view,arch_db:project.portal_my_projects +#: model_terms:ir.ui.view,arch_db:project.view_project +msgid "Projects" +msgstr "المشاريع" + +#. module: project +#: model:ir.ui.menu,name:project.menu_main_pm +msgid "Project" +msgstr "المشروع" + +#. module: project +#: model_terms:ir.ui.view,arch_db:project.edit_project +msgid "Tasks In Progress" +msgstr "المهام قيد التنفيذ" + +#. module: project_base +#: model:ir.model.fields,field_description:project_base.field_project_task__task_progress +msgid "Task Progress" +msgstr "نسبة الانجاز" diff --git a/odex25_project/project_base/i18n/ar_001.po b/odex25_project/project_base/i18n/ar_001.po new file mode 100644 index 000000000..e7ada4c5a --- /dev/null +++ b/odex25_project/project_base/i18n/ar_001.po @@ -0,0 +1,2142 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * project_base +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-06-03 08:58+0000\n" +"PO-Revision-Date: 2024-06-03 08:58+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: project_base +#: code:addons/project_base/models/project_phase.py:0 +#, python-format +msgid " For Reasone: %s" +msgstr "" + +#. module: project_base +#: code:addons/project_base/wizard/project_hold_reason.py:0 +#, python-format +msgid " with Reason: %s" +msgstr "" + +#. module: project_base +#: model_terms:ir.ui.view,arch_db:project_base.view_edit_project_phase_wizard +msgid "" +"\n" +" Kindly make sure to Save current project stages before edit.\n" +" " +msgstr "" + +#. module: project_base +#: model_terms:ir.ui.view,arch_db:project_base.project_detail_qweb_report +msgid "Country" +msgstr "" + +#. module: project_base +#: model_terms:ir.ui.view,arch_db:project_base.project_detail_qweb_report +msgid "Customer" +msgstr "" + +#. module: project_base +#: model_terms:ir.ui.view,arch_db:project_base.project_detail_qweb_report +msgid "Finish Date" +msgstr "" + +#. module: project_base +#: model_terms:ir.ui.view,arch_db:project_base.project_detail_qweb_report +msgid "Kick-Off Date" +msgstr "" + +#. module: project_base +#: model_terms:ir.ui.view,arch_db:project_base.project_detail_qweb_report +msgid "Project Category" +msgstr "" + +#. module: project_base +#: model_terms:ir.ui.view,arch_db:project_base.project_detail_qweb_report +msgid "Project Manager" +msgstr "" + +#. module: project_base +#: model_terms:ir.ui.view,arch_db:project_base.project_detail_qweb_report +msgid "Sale Order" +msgstr "" + +#. module: project_base +#: model_terms:ir.ui.view,arch_db:project_base.project_detail_qweb_report +msgid "Start Date" +msgstr "" + +#. module: project_base +#: model_terms:ir.ui.view,arch_db:project_base.project_detail_qweb_report +msgid "stage" +msgstr "" + +#. module: project_base +#: model_terms:ir.ui.view,arch_db:project_base.view_new_project_kanban +msgid "" +msgstr "" + +#. module: project_base +#: model_terms:ir.ui.view,arch_db:project_base.view_edit_project_inherit_form +msgid "" +"\n" +" Project Phase updated %s