def get_admin_business_type_schema(): schema = SQLAlchemySchemaNode( BusinessType, includes=( 'label', 'project_type_id', 'other_project_types' ) ) customize_field( schema, "label", validator=get_deferred_unique_label_validator(BusinessType), ) customize_field( schema, 'project_type_id', widget=get_deferred_model_select(ProjectType), validator=get_deferred_unique_project_type_default ) customize_field( schema, 'other_project_types', children=get_sequence_child_item(ProjectType), widget=get_deferred_model_select_checkbox( ProjectType, filters=[['active', True]], ) ) return schema
class SaleProductGroup(DBBASE): """ A product group model """ __table_args__ = default_table_args id = Column(Integer, primary_key=True) label = Column(String(255), nullable=False) ref = Column(String(100), nullable=True) title = Column(String(255), default="") description = Column(Text(), default='') products = relationship( "SaleProduct", secondary=PRODUCT_TO_GROUP_REL_TABLE, info={ 'colanderalchemy': { # Permet de sélectionner des éléments existants au lieu # d'insérer des nouveaux à chaque fois 'children': forms.get_sequence_child_item(SaleProduct), } }) category_id = Column(ForeignKey('sale_product_category.id')) category = relationship( SaleProductCategory, backref=backref('product_groups'), info={'colanderalchemy': forms.EXCLUDED}, ) def __json__(self, request): """ Json repr of our model """ return dict( id=self.id, label=self.label, ref=self.ref, title=self.title, description=self.description, products=[product.__json__(request) for product in self.products], category_id=self.category_id, ) @property def company(self): return self.category.company
def get_schema(self, submitted): model_type = submitted['type'] model = CRITERION_MODELS.get(model_type) schema = SQLAlchemySchemaNode( model, excludes=('type_', 'id'), ) if model_type in ('or', 'and'): schema['criteria'] = colander.SchemaNode( colander.Sequence(), forms.get_sequence_child_item(BaseStatisticCriterion)[0], name='criteria', missing=colander.drop, ) return schema
def get_admin_business_type_schema(): schema = SQLAlchemySchemaNode(BusinessType, includes=('label', 'project_type_id', 'other_project_types')) customize_field( schema, "label", validator=get_deferred_unique_label_validator(BusinessType), ) customize_field(schema, 'project_type_id', widget=get_deferred_model_select(ProjectType), validator=get_deferred_unique_project_type_default) customize_field(schema, 'other_project_types', children=get_sequence_child_item(ProjectType), widget=get_deferred_model_select_checkbox( ProjectType, filters=[['active', True]], )) return schema
class SaleTrainingGroup(SaleProductGroup): """ A product group model :param id: unique id :param goals: goals of title of the training item :param prerequisites: prerequisites to subscribe to the training session :param for_who: target of the training item :param duration: duration of the training item :param content: content of the training item :param teaching_method: teaching_method used in training session :param logistics_means: logistics_means implemented for the training session :param more_stuff: Les plus... :param evaluation: evaluation criteria :param place: place if the training session :param modality: modality of the training session :param types: types of the training :param date: date og the training session :param price: price of the training session :param free_1: free input :param free_2: free input :param free_3: free input :param company_id: company that owns the training :param company_id: company that owns the group """ __table_args__ = default_table_args __mapper_args__ = {'polymorphic_identity': 'training'} id = Column(ForeignKey('sale_product_group.id'), primary_key=True) goals = Column( String(255), default='', ) prerequisites = Column(String(255), default='') for_who = Column(String(255), default='') duration = Column(String(255), nullable=False, default='') content = Column(String(255), default='') teaching_method = Column(String(255), default='') logistics_means = Column(String(255), default='') more_stuff = Column(String(255), default='') evaluation = Column(String(255), default='') place = Column(String(255), default='') modality_one = Column(Boolean(), default=False) modality_two = Column(Boolean(), default=False) types = relationship( 'TrainingTypeOptions', secondary=TRAINING_TYPE_TO_TRAINING_GROUP_REL_TABLE, info={ 'export': { 'related_key': 'label' }, 'colanderalchemy': { # Permet de sélectionner des éléments existants au lieu # d'insérer des nouveaux à chaque fois 'children': forms.get_sequence_child_item(TrainingTypeOptions), } }, ) date = Column(String(255), default='') price = Column(String(255), default='') free_1 = Column(String(255), default='') free_2 = Column(String(255), default='') free_3 = Column(String(255), default='') category = relationship( SaleProductCategory, backref=backref('training_groups'), info={'colanderalchemy': forms.EXCLUDED}, ) def __json__(self, request): """ Json repr of our model """ result = SaleProductGroup.__json__(self, request) result.update( id=self.id, goals=self.goals, prerequisites=self.prerequisites, for_who=self.for_who, duration=self.duration, content=self.content, teaching_method=self.teaching_method, logistics_means=self.logistics_means, more_stuff=self.more_stuff, evaluation=self.evaluation, place=self.place, modality_one=self.modality_one, modality_two=self.modality_two, types=[type.__json__(request) for type in self.types], date=self.date, price=self.price, free_1=self.free_1, free_2=self.free_2, free_3=self.free_3, ) return result @property def company(self): return self.category.company
def _customize_task_fields(schema): """ Add Field customization to the task form schema :param obj schema: The schema to modify """ schema.after_bind = task_after_bind customize = functools.partial(forms.customize_field, schema) customize("id", widget=deform.widget.HiddenWidget(), missing=colander.drop) customize( "status", widget=deform.widget.SelectWidget(values=zip(ALL_STATES, ALL_STATES)), validator=colander.OneOf(ALL_STATES), ) customize( "status_comment", widget=deform.widget.TextAreaWidget(), ) customize( "status_person_id", widget=get_deferred_user_choice(), ) customize( "description", widget=deform.widget.TextAreaWidget(), validator=forms.textarea_node_validator, missing=colander.required, ) customize("date", missing=colander.required) for field_name in "ht", "ttc", "tva", "expenses_ht": customize(field_name, typ=AmountType(5)) customize( "address", widget=deform.widget.TextAreaWidget(), validator=forms.textarea_node_validator, missing=colander.required, ) customize( "workplace", widget=deform.widget.TextAreaWidget(), ) customize( "payment_conditions", widget=deform.widget.TextAreaWidget(), validator=forms.textarea_node_validator, missing=colander.required, ) customize( "mentions", children=forms.get_sequence_child_item(TaskMention), ) customize( "line_groups", validator=colander.Length(min=1, min_err=u"Une entrée est requise"), missing=colander.required, ) if 'line_groups' in schema: child_schema = schema['line_groups'].children[0] _customize_tasklinegroup_fields(child_schema) if "discount_lines" in schema: child_schema = schema['discount_lines'].children[0] _customize_discountline_fields(child_schema) return schema
def _customize_task_fields(schema): """ Add Field customization to the task form schema :param obj schema: The schema to modify """ schema.after_bind = task_after_bind customize = functools.partial(forms.customize_field, schema) customize("id", widget=deform.widget.HiddenWidget(), missing=colander.drop) customize( "status", widget=deform.widget.SelectWidget(values=zip(ALL_STATES, ALL_STATES)), validator=colander.OneOf(ALL_STATES), ) customize( "status_comment", widget=deform.widget.TextAreaWidget(), ) customize( "status_person_id", widget=get_deferred_user_choice(), ) customize( "business_type_id", validator=business_type_id_validator, ) customize( "description", widget=deform.widget.TextAreaWidget(), validator=forms.textarea_node_validator, missing=colander.required, ) customize("date", missing=colander.required) for field_name in "ht", "ttc", "tva", "expenses_ht": customize( field_name, typ=AmountType(5) ) customize( "address", widget=deform.widget.TextAreaWidget(), validator=forms.textarea_node_validator, missing=colander.required, ) customize( "workplace", widget=deform.widget.TextAreaWidget(), ) customize( "payment_conditions", widget=deform.widget.TextAreaWidget(), validator=forms.textarea_node_validator, missing=colander.required, ) customize( "mentions", children=forms.get_sequence_child_item(TaskMention), ) customize( "line_groups", validator=colander.Length(min=1, min_err=u"Une entrée est requise"), missing=colander.required, ) if 'line_groups' in schema: child_schema = schema['line_groups'].children[0] _customize_tasklinegroup_fields(child_schema) if "discount_lines" in schema: child_schema = schema['discount_lines'].children[0] _customize_discountline_fields(child_schema) return schema
class Task(Node): """ Metadata pour une tâche (estimation, invoice) """ __tablename__ = 'task' __table_args__ = default_table_args __mapper_args__ = {'polymorphic_identity': 'task'} _autonomie_service = TaskService __colanderalchemy_config__ = { 'after_bind': task_after_bind, } id = Column( Integer, ForeignKey('node.id'), info={ 'colanderalchemy': { 'exclude': deform.widget.HiddenWidget() }, 'export': forms.EXCLUDED }, primary_key=True, ) phase_id = Column( ForeignKey('phase.id'), info={ 'colanderalchemy': forms.EXCLUDED, "export": forms.EXCLUDED, }, ) status = Column( String(10), info={ 'colanderalchemy': { 'title': u"Statut", 'widget': deform.widget.SelectWidget(values=zip(ALL_STATES, ALL_STATES)), "validator": colander.OneOf(ALL_STATES), }, 'export': forms.EXCLUDED }) status_comment = Column( Text, info={ "colanderalchemy": { "title": u"Commentaires", 'widget': deform.widget.TextAreaWidget() }, 'export': forms.EXCLUDED }, default="", ) status_person_id = Column( ForeignKey('accounts.id'), info={ 'colanderalchemy': { "title": u"Dernier utilisateur à avoir modifié le document", 'widget': get_deferred_user_choice() }, "export": forms.EXCLUDED, }, ) status_date = Column(Date(), default=datetime.date.today, info={ 'colanderalchemy': { "title": u"Date du dernier changement de statut", }, 'export': forms.EXCLUDED }) date = Column(Date(), info={ "colanderalchemy": { "title": u"Date du document", "missing": colander.required } }, default=datetime.date.today) owner_id = Column( ForeignKey('accounts.id'), info={ 'colanderalchemy': forms.EXCLUDED, "export": forms.EXCLUDED, }, ) description = Column( Text, info={ 'colanderalchemy': { "title": u"Objet", 'widget': deform.widget.TextAreaWidget(), 'validator': forms.textarea_node_validator, 'missing': colander.required, } }, ) ht = Column(BigInteger(), info={ 'colanderalchemy': { "title": u"Montant HT (cache)", "typ": AmountType(5), }, 'export': forms.EXCLUDED, }, default=0) tva = Column(BigInteger(), info={ 'colanderalchemy': { "title": u"Montant TVA (cache)", "typ": AmountType(5), }, 'export': forms.EXCLUDED, }, default=0) ttc = Column(BigInteger(), info={ 'colanderalchemy': { "title": u"Montant TTC (cache)", "typ": AmountType(5), }, 'export': forms.EXCLUDED, }, default=0) company_id = Column( Integer, ForeignKey('company.id'), info={ 'colanderalchemy': forms.EXCLUDED, 'export': forms.EXCLUDED, }, ) project_id = Column( Integer, ForeignKey('project.id'), info={ 'colanderalchemy': forms.EXCLUDED, 'export': forms.EXCLUDED, }, ) customer_id = Column( Integer, ForeignKey('customer.id'), info={ 'colanderalchemy': forms.EXCLUDED, 'export': forms.EXCLUDED, }, ) project_index = deferred( Column( Integer, info={ 'colanderalchemy': { "title": u"Index dans le projet", }, 'export': forms.EXCLUDED, }, ), group='edit', ) company_index = deferred( Column( Integer, info={ 'colanderalchemy': { "title": u"Index du document à l'échelle de l'entreprise", }, 'export': forms.EXCLUDED, }, ), group='edit', ) official_number = Column( Integer, info={ 'colanderalchemy': { "title": u"Identifiant du document (facture/avoir)", }, 'export': { 'label': u"Numéro de facture" }, }, default=None, ) internal_number = deferred(Column( String(255), default=None, info={ 'colanderalchemy': { "title": u"Identifiant du document dans la CAE", }, 'export': forms.EXCLUDED, }), group='edit') display_units = deferred(Column(Integer, info={ 'colanderalchemy': { "title": u"Afficher le détail ?", "validator": colander.OneOf((0, 1)) }, 'export': forms.EXCLUDED, }, default=0), group='edit') # Not used in latest invoices expenses = deferred(Column(BigInteger(), info={ 'colanderalchemy': forms.EXCLUDED, 'export': forms.EXCLUDED, }, default=0), group='edit') expenses_ht = deferred( Column(BigInteger(), info={ 'colanderalchemy': { 'typ': AmountType(5), 'title': u'Frais', }, 'export': forms.EXCLUDED, }, default=0), group='edit', ) address = deferred( Column( Text, default="", info={ 'colanderalchemy': { 'title': u'Adresse', 'widget': deform.widget.TextAreaWidget(), 'validator': forms.textarea_node_validator, 'missing': colander.required, }, 'export': forms.EXCLUDED, }, ), group='edit', ) workplace = deferred( Column(Text, default='', info={ 'colanderalchemy': { 'title': u"Lieu d'éxécution des travaux", 'widget': deform.widget.TextAreaWidget(), } })) payment_conditions = deferred( Column( Text, info={ 'colanderalchemy': { "title": u"Conditions de paiement", 'widget': deform.widget.TextAreaWidget(), 'validator': forms.textarea_node_validator, 'missing': colander.required, }, 'export': forms.EXCLUDED, }, ), group='edit', ) round_floor = deferred( Column(Boolean(), default=False, info={ 'colanderalchemy': { 'exlude': True, 'title': u"Méthode d'arrondi 'à l'ancienne' ? (floor)" }, 'export': forms.EXCLUDED, }), group='edit', ) prefix = Column(String(15), default='', info={ "colanderalchemy": { 'title': u"Préfixe du numéro de facture", }, 'export': forms.EXCLUDED, }) # Organisationnal Relationships status_person = relationship( "User", primaryjoin="Task.status_person_id==User.id", backref=backref( "taskStatuses", info={ 'colanderalchemy': forms.EXCLUDED, 'export': forms.EXCLUDED, }, ), info={ 'colanderalchemy': forms.EXCLUDED, 'export': forms.EXCLUDED, }, ) owner = relationship( "User", primaryjoin="Task.owner_id==User.id", backref=backref( "ownedTasks", info={ 'colanderalchemy': forms.EXCLUDED, 'export': forms.EXCLUDED, }, ), info={ 'colanderalchemy': forms.EXCLUDED, 'export': forms.EXCLUDED, }, ) phase = relationship( "Phase", primaryjoin="Task.phase_id==Phase.id", backref=backref( "tasks", order_by='Task.date', info={ 'colanderalchemy': forms.EXCLUDED, 'export': forms.EXCLUDED, }, ), info={ 'colanderalchemy': forms.EXCLUDED, 'export': forms.EXCLUDED, }, ) company = relationship( "Company", primaryjoin="Task.company_id==Company.id", info={ 'colanderalchemy': forms.EXCLUDED, 'export': { 'related_key': "name", "label": "Entreprise" }, }, ) project = relationship( "Project", primaryjoin="Task.project_id==Project.id", info={ 'colanderalchemy': forms.EXCLUDED, 'export': forms.EXCLUDED, }, ) customer = relationship( "Customer", primaryjoin="Customer.id==Task.customer_id", backref=backref( 'tasks', order_by='Task.date', info={ 'colanderalchemy': forms.EXCLUDED, "export": forms.EXCLUDED, }, ), info={ 'colanderalchemy': forms.EXCLUDED, 'export': { 'related_key': 'label', 'label': u"Client" }, }, ) # Content relationships discounts = relationship( "DiscountLine", info={ 'colanderalchemy': { 'title': u"Remises" }, 'export': forms.EXCLUDED, }, order_by='DiscountLine.tva', cascade="all, delete-orphan", back_populates='task', ) payments = relationship( "Payment", primaryjoin="Task.id==Payment.task_id", info={ 'colanderalchemy': forms.EXCLUDED, 'export': forms.EXCLUDED, }, order_by='Payment.date', cascade="all, delete-orphan", back_populates='task', ) mentions = relationship( "TaskMention", secondary=TASK_MENTION, order_by="TaskMention.order", back_populates="tasks", info={ 'colanderalchemy': { 'children': forms.get_sequence_child_item(TaskMention), }, 'export': forms.EXCLUDED, }, ) line_groups = relationship( "TaskLineGroup", order_by='TaskLineGroup.order', cascade="all, delete-orphan", collection_class=ordering_list('order'), info={ 'colanderalchemy': { 'title': u"Unités d'oeuvre", "validator": colander.Length(min=1, min_err=u"Une entrée est requise"), "missing": colander.required }, 'export': forms.EXCLUDED, }, primaryjoin="TaskLineGroup.task_id==Task.id", back_populates='task', ) statuses = relationship( "TaskStatus", order_by="desc(TaskStatus.status_date), desc(TaskStatus.id)", cascade="all, delete-orphan", back_populates='task', info={ 'colanderalchemy': forms.EXCLUDED, 'export': forms.EXCLUDED, }) _name_tmpl = u"Task {}" _number_tmpl = u"{s.project.code}_{s.customer.code}_T{s.project_index}\ _{s.date:%m%y}" state_manager = None def __init__(self, company, customer, project, phase, user): company_index = self._get_company_index(company) project_index = self._get_project_index(project) self.status = 'draft' self.company = company self.customer = customer self.address = customer.full_address self.project = project self.phase = phase self.owner = user self.status_person = user self.date = datetime.date.today() self.set_numbers(company_index, project_index) # We add a default task line group self.line_groups.append(TaskLineGroup(order=0)) def _get_project_index(self, project): """ Return the index of the current object in the associated project :param obj project: A Project instance in which we will look to get the current doc index :returns: The next number :rtype: int """ return -1 def _get_company_index(self, company): """ Return the index of the current object in the associated company :param obj company: A Company instance in which we will look to get the current doc index :returns: The next number :rtype: int """ return -1 def set_numbers(self, company_index, project_index): """ Handle all attributes related to the given number :param int company_index: The index of the task in the company :param int project_index: The index of the task in its project """ if company_index is None or project_index is None: raise Exception("Indexes should not be None") self.company_index = company_index self.project_index = project_index self.internal_number = self._number_tmpl.format(s=self) self.name = self._name_tmpl.format(project_index) @property def default_line_group(self): return self.line_groups[0] def __json__(self, request): """ Return the datas used by the json renderer to represent this task """ return dict( id=self.id, name=self.name, created_at=self.created_at.isoformat(), updated_at=self.updated_at.isoformat(), phase_id=self.phase_id, status=self.status, status_comment=self.status_comment, status_person_id=self.status_person_id, # status_date=self.status_date.isoformat(), date=self.date.isoformat(), owner_id=self.owner_id, description=self.description, ht=integer_to_amount(self.ht, 5), tva=integer_to_amount(self.tva, 5), ttc=integer_to_amount(self.ttc, 5), company_id=self.company_id, project_id=self.project_id, customer_id=self.customer_id, project_index=self.project_index, company_index=self.company_index, official_number=self.official_number, internal_number=self.internal_number, display_units=self.display_units, expenses_ht=integer_to_amount(self.expenses_ht, 5), address=self.address, workplace=self.workplace, payment_conditions=self.payment_conditions, prefix=self.prefix, status_history=[ status.__json__(request) for status in self.statuses ], discounts=[ discount.__json__(request) for discount in self.discounts ], payments=[payment.__json__(request) for payment in self.payments], mentions=[mention.id for mention in self.mentions], line_groups=[ group.__json__(request) for group in self.line_groups ], attachments=[ f.__json__(request) for f in self.children if f.type_ == 'file' ]) def set_status(self, status, request, **kw): """ set the status of a task through the state machine """ return self.state_manager.process(status, self, request, **kw) def check_status_allowed(self, status, request, **kw): return self.state_manager.check_allowed(status, self, request) @validates('status') def change_status(self, key, status): """ fired on status change, stores a new taskstatus for each status change """ log.debug(u"# Task status change #") actual_status = self.status log.debug(u" + was {0}, becomes {1}".format(actual_status, status)) return status def get_company(self): """ Return the company owning this task """ return self.company def get_customer(self): """ Return the customer of the current task """ return self.customer def get_company_id(self): """ Return the id of the company owning this task """ return self.company.id def __repr__(self): return u"<Task status:{s.status} id:{s.id}>".format(s=self) def get_groups(self): return [group for group in self.line_groups if group.lines] @property def all_lines(self): """ Returns a list with all task lines of the current task """ result = [] for group in self.line_groups: result.extend(group.lines) return result def get_tva_objects(self): return self._autonomie_service.get_tva_objects(self) @classmethod def get_valid_tasks(cls, *args): return cls._autonomie_service.get_valid_tasks(cls, *args) @classmethod def get_waiting_estimations(cls, *args): return cls._autonomie_service.get_waiting_estimations(*args) @classmethod def get_waiting_invoices(cls, *args): return cls._autonomie_service.get_waiting_invoices(cls, *args)