endi.models.services package

Submodules

endi.models.services.bpf module

class endi.models.services.bpf.BPFService

Bases : object

Handle BPF initialization according to current law

CERFA_VERSIONS = {'10443*14': <class 'endi.models.services.bpf.Cerfa_10443_14'>, '10443*15': <class 'endi.models.services.bpf.Cerfa_10443_15'>, '10443*16': <class 'endi.models.services.bpf.Cerfa_10443_16'>}
classmethod check_businesses_bpf(query, financial_year)
classmethod gen_bpf(business, financial_year)
classmethod get(business_id, financial_year)
classmethod get_or_create(business_id, financial_year)
classmethod get_spec_from_year(year)
classmethod get_spec_name_from_year(year)
class endi.models.services.bpf.BPFSpecInterface

Bases : object

classmethod stream_csv_rows(query)
Paramètres:

Query<BPFData> (query) –

class endi.models.services.bpf.BusinesssBPFDataMigrator_15to16

Bases : object

Tranform Cerfa 10443*15 data into 10443*15 data

Tries to tranform a BusinessBPFData from 2020 that was (wrongly) filled using a 10443*15 form into 10443*16 form data. Does its best, but errors could remain.

INCOME_SOURCES_MAPPING = {0: 0, 1: 2, 2: 4, 3: 5, 4: 6, 5: 8, 6: 7, 7: 10, 8: 20, 9: 21, 10: 22, 11: 23, 12: 24, 13: 30, 14: 31, 15: 32, 16: 32}
TRAINEE_TYPE_MAPPING = {0: 0, 1: 2, 2: 2, 3: 3, 4: 4}
TRAINING_GOALS_MAPPING = {0: 0, 1: 1, 2: 2, 3: 3, 4: 10, 5: 11, 6: 12, 7: 13, 8: 14}
classmethod migrate(bpf_data: BusinessBPFData) None

Mutate the bpf_data, trying to map data (wrongly) filled in a 10443*15 into 10443*16 form.

class endi.models.services.bpf.Cerfa_10443_14

Bases : BPFSpecInterface

https://www.formulaires.modernisation.gouv.fr/gf/getNotice.do?cerfaFormulaire=10443&cerfaNotice=50199 https://www.formulaires.modernisation.gouv.fr/gf/cerfa_10443.do

INCOME_SOURCES = [(0, 'Entreprises pour la formation de leurs salariés', []), (None, 'Organismes paritaires collecteurs ou gestionnaires des fonds de la formation', [(1, 'contrats de professionnalisation'), (2, 'congés individuels de formation'), (3, 'compte personnel de formation'), (4, 'autres dispositifs (plan de formation, périodes de professionnalisation, …)'), (5, 'pour des formations dispensées dans le cadre d’autres dispositifs (plan de formation, périodes de professionnalisation')]), (6, "Fonds d'assurance", []), (7, 'Pouvoirs publics pour la formation de leurs agents (Etat, collectivités territoriales, établissements publics à caractère administratif)', []), (None, 'Pouvoirs publics pour la formation de publics spécifiques', [(8, 'Instances européennes'), (9, 'État'), (10, 'Conseils régionaux'), (11, 'Pôle emploi'), (12, 'Autres ressources publiques')]), (13, 'Contrats conclus avec des personnes à titre individuel et à leurs frais', []), (14, 'Contrats conclus avec d’autres organismes de formation', []), (15, 'Produits résultant de la vente d’outils pédagogiques', []), (16, 'Autres produits au titre de la formation professionnelle continue', [])]
TRAINEE_TYPES = [(0, 'Salariés bénéficiant d’un financement par l’employeur, par un OPCA ou un OPACIF', []), (1, 'Personnes en recherche d’emploi bénéficiant d’un financement public', []), (2, 'Personnes en recherche d’emploi bénéficiant d’un financement OPCA', []), (3, 'Particuliers à leurs propres frais', []), (4, 'Autres stagiaires', [])]
TRAINING_GOALS = [(None, 'Formations visant un diplôme ou un titre à finalité professionnelle (hors certificat de qualification professionnelle) inscrit au Répertoire national des certifications professionnelles (RNCP)', [(0, 'Niveau I et II (licence, maîtrise, master, DEA, DESS, diplôme d’ingénieur)'), (1, 'Niveau III (BTS, DUT, écoles de formation sanitaire et sociale…)'), (2, 'Niveau III (BTS, DUT, écoles de formation sanitaire et sociale…)'), (3, 'Niveau IV (BAC professionnel, BT, BP, BM…)')]), (4, 'Certificat de qualification professionnelle (CQP)', []), (5, 'Certification et/ou une habilitation inscrite à l’inventaire de la CNCP', []), (6, 'Autres formations professionnelles continues', []), (7, 'Bilan de compétences', []), (8, "Actions d'accompagnement à la validation des acquis d'expérience", [])]
classmethod build_data_dict(bpf_data_query)
classmethod build_template_context(bpf_data_query)
classmethod cost_stats(bpf_data_query)

Data for « D. BILAN FINANCIER HORS TAXES »

Returns dict:

of floats (keys: total, subcontracted, internal)

classmethod get_income_sources_ids()
classmethod get_trainee_types_ids()
classmethod get_training_goals_ids()
classmethod has_subcontract_stats(bpf_data_query)

Data for « F - 2. ACTIVITÉ EN PROPRE DE L’ORGANISME »

Gather data for everything that is not subcontract

Renvoie:

info as row attributes : total_hours and headcount

Rtype sqlalchemy.engine.RowProxy:

classmethod income_stats(bpf_data_query)

Data for « C. BILAN FINANCIER HORS TAXES »

Returns sqlalchemy.orm.Query:

classmethod is_not_subcontract_stats(bpf_data_query)

Data for « F - 2. ACTIVITÉ EN PROPRE DE L’ORGANISME »

Gather data for everything that is not subcontract

Renvoie:

info as row attributes : total_hours and headcount

Rtype sqlalchemy.engine.RowProxy:

classmethod is_subcontract_stats(bpf_data_query)

Data for « F - 2. ACTIVITÉ EN PROPRE DE L’ORGANISME »

Gather data for everything that is subcontract

Renvoie:

info as row attributes : total_hours and headcount

Rtype sqlalchemy.engine.RowProxy:

ods_template = '/home/docs/checkouts/readthedocs.org/user_builds/endi/checkouts/latest/docs/source/../../endi/sample_templates/bpf/CERFA 10443*14.ods'
classmethod sum_bpf_datas(bpf_data_query)
classmethod trainee_types_stats(bpf_data_query)

Data for « F - 1. TYPE DE STAGIAIRES DE L’ORGANISME »

Renvoie:

stats for each type of trainee. List indexes match TRAINEE_TYPES order

Type renvoyé:

list of dict like {“headcount”: 42, “total_hours”: 12}.

classmethod training_goals_stats(bpf_data_query)

Data for « F - 3. OBJECTIF GÉNÉRAL DES PRESTATIONS DISPENSÉES »

Renvoie:

stats for each type of training goal. List indexes match TRAINING_GOALS order

Type renvoyé:

list of dict like {“headcount”: 42, “total_hours”: 12}.

classmethod training_speciality_stats(bpf_data_query)

Data for « F - 4. SPÉCIALITÉS DE FORMATION »

Type renvoyé:

iterator of dicts

class endi.models.services.bpf.Cerfa_10443_15

Bases : Cerfa_10443_14

Contains strictly same data/rules as CERFA 10443*14

class endi.models.services.bpf.Cerfa_10443_16

Bases : Cerfa_10443_15

https://www.formulaires.modernisation.gouv.fr/gf/getNotice.do?cerfaFormulaire=10443&cerfaNotice=50199 https://www.formulaires.modernisation.gouv.fr/gf/cerfa_10443.do

INCOME_SOURCES = [(0, 'Entreprises pour la formation de leurs salariés', []), (None, 'Organismes gestionnaires des fonds de la formation professionnelle pour des actions dispensées dans le cadre des :', [(1, "contrats d'apprentissage"), (2, 'contrats de professionnalisation'), (3, 'promotion ou reconversion par alternance'), (4, 'congés individuels de formation et des projets de transition professionnelle'), (5, 'compte personnel de formation'), (6, 'dispositifs spécifiques pour les personnes en recherche d’emploi'), (7, 'dispositifs spécifiques pour les travailleurs non-salariés'), (8, 'plan de développement des compétences ou d’autres dispositifs')]), (10, 'Pouvoirs publics pour la formation de leurs agents (Etat, collectivités territoriales, établissements publics à caractère administratif)', []), (None, 'Pouvoirs publics pour la formation de publics spécifiques', [(20, 'Instances européennes'), (21, 'État'), (22, 'Conseils régionaux'), (23, 'Pôle emploi'), (24, 'Autres ressources publiques')]), (30, 'Contrats conclus avec des personnes à titre individuel et à leurs frais', []), (31, 'Contrats conclus avec d’autres organismes de formation (y compris CFA)', []), (32, 'Autres produits au titre de la formation professionnelle continue', [])]
TRAINEE_TYPES = [(0, 'Salariés d’employeurs privés hors apprentis', []), (1, 'Apprentis', []), (2, 'Personnes en recherche d’emploi formées par votre organisme de formation', []), (3, 'Particuliers à leurs propres frais formés par votre organisme de formation', []), (4, 'Autres stagiaires', [])]
TRAINING_GOALS = [(None, 'Formations visant un diplôme ou un titre à finalité professionnelle (hors certificat de qualification professionnelle) inscrit au Répertoire national des certifications professionnelles (RNCP)', [(0, 'Niveau 6 à 8 (Licence, Master, diplôme d’ingénieur, Doctorat…)....'), (1, 'Niveau 5 (BTS, DUT, écoles de formation sanitaire et sociale …) .'), (2, 'Niveau 4 (BAC professionnel, BT, BP, BM…)'), (3, 'Niveau 3 (BEP, CAP…).....'), (4, 'Niveau 2'), (5, 'Certificat de qualification professionnelle (CQP) sans niveau de qualification')]), (10, 'Formations visant une certification (dont CQP) ou une habilitation enregistrée au répertoire spécifique (RS)', []), (11, 'Formations visant un CQP non enregistré au RNCP ou au RS', []), (12, 'Autres formations professionnelles', []), (13, 'Bilan de compétences', []), (14, "Actions d'accompagnement à la validation des acquis d'expérience", [])]
classmethod build_data_dict(bpf_data_query)
ods_template = '/home/docs/checkouts/readthedocs.org/user_builds/endi/checkouts/latest/docs/source/../../endi/sample_templates/bpf/CERFA 10443*16.ods'
endi.models.services.bpf.collect_categories_ids(categories)

Collects ids, and return a flat list of ids.

Paramètres:

categories (list) – flat or nested (max 1 level) categories in a list

Yield:

int

endi.models.services.business module

endi.models.services.business_status module

endi.models.services.company module

Company query service

class endi.models.services.company.CompanyService

Bases : object

classmethod employs(company, uid)

Check if the given company employs User with id uid

Paramètres:
  • company (obj) – The current Company

  • uid (int) – The user id

Type renvoyé:

bool

classmethod format_label_from_datas(company_class, company_datas, with_select_search_datas=False)

Return the company’s label to display Add employees infos to company’s name if config ask to Add search datas (employees, code_compta) if asked

company_datas:

can be either - a Company object - an SqlAlchemy.Row : (

id, name, code_compta, active, nb_employees, employees_list

) - a dict : {

“id”: int, “name”: str, “code_compta”: str, “active”: bool, “nb_employees”: int, “employees_list”: str

}

classmethod get_active_employees(company)

Collect active employees

classmethod get_cancelinvoices(instance, valid=False)
classmethod get_companies_select_datas(company_class, request, only_active=False)
classmethod get_contribution(company_id, prefix='')
classmethod get_customer_codes_and_names(company)

Return a query for code and names of customers related to company :param company: the company we’re working on :returns: an orm query loading Customer instances with only the columns we want :rtype: A Sqlalchemy query object

classmethod get_customers(instance, year)
classmethod get_employee_ids(company)

Collect company user_ids

classmethod get_estimations(instance, valid=False)
classmethod get_general_customer_account(instance, prefix='')
classmethod get_general_expense_account(instance, prefix='')
classmethod get_general_supplier_account(instance, prefix='')
classmethod get_id_by_analytical_account(company_class, analytical_account)

Return id of the oldest company with given analytical account

Paramètres:
  • company_class (class) – The Company class

  • analytical_account (str) – The analytical account to get

Renvoie:

Integer or None

classmethod get_invoices(instance, valid=False, not_paid=False)
classmethod get_last_treasury_main_indicator(company)

Retrieve the main indicator’s datas from the last treasury grid of a given company Return {« date », « label », « value »} of the measure

classmethod get_late_invoices(instance)
classmethod get_nb_km_on_period(company, start_date, end_date)

Compute the kilometers declared for a given company on the given period

classmethod get_next_cancelinvoice_index(company)

Return the next available sequence index in the given company

classmethod get_next_estimation_index(company)

Return the next available sequence index in the given company

classmethod get_next_index(company, factory)
classmethod get_next_invoice_index(company)

Return the next available sequence index in the given company

classmethod get_project_codes_and_names(company)

Return a query for code and names of projects related to company

Paramètres:

company – the company we’re working on

Renvoie:

an orm query loading Project instances with only the columns

we want :rtype: A Sqlalchemy query object

classmethod get_rate(company_id: int, rate_name: str, prefix: str = '') float

Renvoie le taux de contribution à appliquer pour cette enseigne (assurance/contribution ou autre)

Les CustomInvoiceBookEntry module créé par endi ont un « name » qui correspond à l’attribut de Company qui permet d’overrider le taux associé

Paramètres:
  • id – Company id

  • prefix (str) – configuration key prefix (ex: internal)

classmethod get_rate_level(company_id: int, rate_name: str, prefix: str = '') str

Renvoie le niveau (cae/company/document) auquel la contribution est définie

Note : Les CustomInvoiceBookEntry module créé par endi ont un « name » qui correspond à l’attribut de Company qui permet d’overrider le taux associé

Paramètres:
  • id – Company id

  • prefix (str) – configuration key prefix (ex: internal)

classmethod get_supplier_codes_and_names(company)

Return a query for code and names of suppliers related to company :param company: the company we’re working on :returns: an orm query loading Supplier instances with only the columns we want :rtype: A Sqlalchemy query object

classmethod get_tasks(instance, offset=None, limit=None)
classmethod get_third_party_customer_account(instance, prefix='')
classmethod get_third_party_supplier_account(instance, prefix='')
classmethod get_total_expenses_and_km_on_period(company, start_date, end_date)

Compute the expense total HT and the kilometers declared for a given company on the given period

classmethod get_total_expenses_on_period(company, start_date, end_date)

Compute the expense total HT for a given company on the given period

classmethod get_total_purchases_on_period(company, start_date, end_date)

Compute the purchase total HT for a given company on the given period

classmethod get_turnover(company, start_date, end_date)

Compute the turnover for a given company on the given period

classmethod has_group_member(company, group_name)

Check if the company has a trainer in its employees

Paramètres:
  • company (obj) – A Company instance

  • group_name (str) – The name of the group to check for

Renvoie:

A boolean

classmethod label_datas_query(company_class, request, only_active=False)
classmethod query_for_select_with_trainer(company_class, request)

Build a query suitable for deform select widgets population

Paramètres:

company_class (class) – The Company class

Renvoie:

A sqlalchemy query object

endi.models.services.find_company module

class endi.models.services.find_company.FindCompanyService

Bases : object

Tools used to retrieve company informations like :

employee logins

find company from node

classmethod find_company_id_from_node(node_instance)
classmethod find_employees_login_from_node(node_instance)

endi.models.services.mixins module

class endi.models.services.mixins.BusinessLinkedServiceMixin

Bases : object

Methods to be added on a BusinessLinkedModelMixin related service

The inheriting service must be targeting a model that inherits BusinessLinkedModelMixin.

static linkable(cls, business)

Return the objects available for linking with a given business

Paramètres:
  • class (parent_model) –

  • parent_model_company_id_field – the model class attribute holding company link

Rtype query of BaseExpenseLine:

static query_linked_to(cls, target: BusinessMetricsMixin)

endi.models.services.naming module

class endi.models.services.naming.NamingService

Bases : object

Handles naming overrides per business type

Names sources are (specific to general) : - from Task.frozen_settings attribute (on Task models) - from db (LabelOverride) - default hardcoded labels

DEFAULT_LABELS = {'cancelinvoice': 'Avoir', 'estimation': 'Devis', 'internalcancelinvoice': 'Avoir interne', 'internalestimation': 'Devis interne', 'internalinvoice': 'Facture interne', 'invoice': 'Facture', 'signed_agreement': 'Bon pour accord'}
SUPPORTED_LABEL_KEYS = ['estimation', 'invoice', 'cancelinvoice', 'internalinvoice', 'internalcancelinvoice', 'internalestimation', 'signed_agreement']
classmethod get_default_label(label_key)
classmethod get_label_for_business_type_id(label_key: str, business_type_id: int) str
Renvoie:

label from LabelOverride if any, default label else.

classmethod get_label_for_context(label_key: str, context: Node) str

Gets the label according to a given context,

Use the more specific source available.

classmethod get_labels_for_business_type_id(business_type_id: int) dict

Return labels set for a given business_id, either overriden or default.

endi.models.services.official_number module

class endi.models.services.official_number.AbstractNumberService

Bases : object

Expose a method to assign templated and unique numbers to a class instance

Must be implemented once per document type (OfficialNumberMixin child class) that needs its own numbering scheme.

classmethod allowed_keys()
classmethod assign_number(request, node: OfficialNumberMixin, template)

This function should be run within an SQL transaction to enforce sequence index unicity.

classmethod get_involved_sequences(invoice, template)

Tell which sequences are to be used and what indexes they will give

Renvoie:

the sequences that would be used by this template and their next index

Type renvoyé:

list of couples [<sequence>, <sequence_number>]

classmethod get_sequences_map()
returns: must include following keys“SEQGLOBAL”, “SEQYEAR”,

“SEQMONTH”, “SEQMONTHANA”

classmethod sequences_map()

Memoized on first call ; this is to avoid import loops.

classmethod validate_template(template)

Validate the correctness of the invoice number template

class endi.models.services.official_number.OfficialNumberFormatter(node, sequences_map)

Bases : Formatter

str.format()-like but with custom vars to allow applying an node number template. containing vars and sequence numbers.

get_value(key, args, kwargs)

endi.models.services.phase module

endi.models.services.project module

endi.models.services.sale_file_requirements module

Service managing file requirements :

Project

Businesses

Tasks (Invoice, Estimation, CancelInvoice)

Has several main responsabilities

  • query requirement definitions

  • Populate the Indicators

  • Handle file events and update the indicators (with cascade)

class endi.models.services.sale_file_requirements.BusinessFileRequirementService

Bases : SaleFileRequirementService

Manage Business file requirements

classmethod check_status(node)

Collect indicators related that concerns the given node

classmethod get_status(node) str
class endi.models.services.sale_file_requirements.ProjectFileRequirementService

Bases : SaleFileRequirementService

Manage Project file requirements

Collect indicators related that concerns the given node

classmethod populate(node)

Generate SaleFileRequirement instances for the given node

Paramètres:

node (obj) – A endi.models.node.Node instance

related to the sale module

class endi.models.services.sale_file_requirements.SaleFileRequirementService

Bases : object

classmethod force_all(node)

Force all indicators that are not successfull

Paramètres:

node (obj) – The associated node

classmethod get_attached_indicators(node, file_type_id=None)

Get all the indicators attached to the given node

Paramètres:
  • node_id (int) – The id of the node

  • file_type_id (int) – The id of the file type

Return indicators related to the given file object

Collect indicators related that concerns the given node

classmethod get_status(node) str
classmethod on_file_add(node, file_object)
classmethod on_file_remove(node, file_object)
classmethod on_file_update(node, file_object)
classmethod populate(node)

Generate SaleFileRequirement instances for the given node

Paramètres:

node (obj) – A endi.models.node.Node instance

related to the sale module

classmethod register(node, file_object, action='add')

Update the Indicators attached to node if one is matching the file_object

Paramètres:

node (obj) – A endi.models.node.Node instance

related to the sale module :param obj file_object: A endi.models.files.File instance that has juste been uploaded :param str action: add/update/delete

class endi.models.services.sale_file_requirements.TaskFileRequirementService

Bases : SaleFileRequirementService

classmethod check_status(node)
classmethod get_other_attachments(node)

List files that are attached to the node but not related to any indicator

Collect indicators that concerns the current Task

classmethod get_status(node) str
endi.models.services.sale_file_requirements.build_indicator_from_requirement_def(business_type_file_type_req: BusinessTypeFileType, node: Node) Optional[SaleFileRequirement]

Initialize an indicator from the given req definition object

Handles dispatch of indicators on the upper levels

  • from Task to Business/Project

  • from Business to Project

endi.models.services.user module

class endi.models.services.user.UserPrefsService

Bases : object

Handles account.user_datas field

That field is a melting-pot for user preferences and things we want to remmember at user scope.

Limitation : properties are stored as text JSON, thus, it has no structure from MySQL standpoint and this is not possible to filter on it at SQL level.

DEFAULT_VALUES = {'expense': {'bookmarks': {}}, 'last_managed_company': None}
classmethod get(request, key)
classmethod set(request, key, value)
class endi.models.services.user.UserService

Bases : object

classmethod authenticate(user_cls, login, password)

Module contents