Source

trytond-contract / contract.py

#This file is part of contract module for Tryton.
#The COPYRIGHT file at the top level of this repository contains
#the full copyright notices and license terms.
from trytond.model import Workflow, ModelSQL, ModelView, fields
from trytond.pool import Pool
from trytond.pyson import If, Eval
from trytond.transaction import Transaction


__all__ = ['ContractService', 'ContractServiceProduct', 'Contract']
_STATES = {
    'readonly': Eval('state') != 'draft',
}
_DEPENDS = ['state']


class ContractService(ModelSQL, ModelView):
    "Contract Service"
    __name__ = 'contract.service'
    name = fields.Char('Name', required=True)
    interval_type = fields.Selection([
            ('day', '01 - Day'),
            ('week', '02 - Week'),
            ('month', '03 - Month'),
            ('year', '04 - Year'),
        ], 'Interval Type', required=True)
    interval_number = fields.Integer('Interval Count', required=True)
    products = fields.One2Many('contract.service.product', 'service',
        'Products', required=True)
    note = fields.Text('Note')

    @staticmethod
    def default_interval():
        return 'monthly'

    @staticmethod
    def default_interval_count():
        return 1


class ContractServiceProduct(ModelSQL, ModelView):
    "Contract Service Product"
    __name__ = 'contract.service.product'
    _rec_name = 'product'
    quantity = fields.Float('Quantity', digits=(16, 2), required=True)
    product = fields.Many2One('product.product', 'Product',
        required=True)
    service = fields.Many2One('contract.service', 'Service',
        ondelete='CASCADE')

    @staticmethod
    def default_quantity():
        return 1


class Contract(Workflow, ModelSQL, ModelView):
    "Contract"
    __name__ = 'contract.contract'
    _rec_name = 'reference'
    company = fields.Many2One('company.company', 'Company', required=True,
        states=_STATES, select=True, domain=[
            ('id', If(Eval('context', {}).contains('company'), '=', '!='),
                Eval('context', {}).get('company', 0)),
            ],
        depends=_DEPENDS)
    reference = fields.Char('Reference', size=None, readonly=True)
    party = fields.Many2One('party.party', 'Party', required=True,
        select=True, states=_STATES, depends=_DEPENDS)
    service = fields.Many2One('contract.service', 'Service',
        states=_STATES, required=True)
    state = fields.Selection([
            ('draft', 'Draft'),
            ('active', 'Active'),
            ('hold', 'Hold'),
            ('cancel', 'Canceled'),
        ], 'State', readonly=True, required=True)
    start_date = fields.Date('Start Date', states=_STATES)
    end_date = fields.Date('End Date', states=_STATES)
    note = fields.Text('Note')

    @classmethod
    def __setup__(cls):
        super(Contract, cls).__setup__()
        cls._error_messages.update({
            'missing_contract_sequence': 'Not available Contract Sequence!',
            })
        cls._transitions |= set((
            ('draft', 'hold'),
            ('draft', 'active'),
            ('hold', 'draft'),
            ('hold', 'active'),
            ('active', 'cancel'),
            ('cancel', 'draft'),
        ))
        cls._buttons.update({
            'cancel': {
                'invisible': ~Eval('state').in_(['active']),
                },
            'draft': {
                'invisible': ~Eval('state').in_(['cancel', 'hold']),
                },
            'hold': {
                'invisible': ~Eval('state').in_(['draft']),
                },
            'active': {
                'invisible': ~Eval('state').in_(['hold', 'draft']),
                },
        })

    @staticmethod
    def default_company():
        return Transaction().context.get('company')

    @staticmethod
    def default_state():
        return 'draft'

    @classmethod
    @ModelView.button
    @Workflow.transition('cancel')
    def cancel(cls, contracts):
        Date = Pool().get('ir.date')
        cancels = []
        for contract in contracts:
            if contract.start_date:
                cancels.append(contract)
        cls.write(cancels, {
            'end_date': Date.today(),
            })

    @classmethod
    @ModelView.button
    @Workflow.transition('draft')
    def draft(cls, contracts):
        pass

    @classmethod
    @ModelView.button
    @Workflow.transition('hold')
    def hold(cls, contracts):
        pass

    @classmethod
    @ModelView.button
    @Workflow.transition('active')
    def active(cls, contracts):
        Date = Pool().get('ir.date')
        actives = []
        for contract in contracts:
            if not contract.start_date:
                actives.append(contract)
        cls.write(actives, {
                'start_date': Date.today()
            })
        cls.set_reference(contracts)

    @classmethod
    def set_reference(cls, contracts):
        '''
        Fill the reference field with the contract sequence
        '''
        pool = Pool()
        Sequence = pool.get('ir.sequence')
        Config = pool.get('contract.configuration')

        config = Config(1)
        if not config.contract_sequence:
            cls.raise_user_error('missing_contract_sequence')
        for contract in contracts:
            if contract.reference:
                continue
            reference = Sequence.get_id(config.contract_sequence.id)
            cls.write([contract], {
                    'reference': reference,
                    })

    @classmethod
    def get_products(cls, contract):
        """
        Get products from contract (contract - service - products)
        :param contract: the BrowseRecord of the contract
        :return: [{'product', 'qty'}]
        """
        lines = []
        for sproduct in contract.service.products:
            lines.append({
                'product': sproduct.product,
                'qty': sproduct.quantity,
            })
        return lines