Advertisement
Guest User

Untitled

a guest
Dec 9th, 2016
132
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 14.04 KB | None | 0 0
  1. # This file is part of Tryton.  The COPYRIGHT file at the top level of
  2. # this repository contains the full copyright notices and license terms.
  3. import datetime
  4. from decimal import Decimal
  5. from itertools import product, groupby
  6.  
  7. from trytond.pool import Pool, PoolMeta
  8. from trytond.pyson import Eval, Bool, If
  9. from trytond.model import Workflow, ModelView, fields, ModelSQL, \
  10.         sequence_ordered
  11. from trytond.wizard import Wizard, StateView, StateTransition, Button
  12. from trytond.transaction import Transaction
  13.  
  14. from trytond.modules.product import price_digits
  15.  
  16. __all__ = ['Configuration', 'Group', 'PurchaseRequestQuotation',
  17.     'CreatePurchaseRequestQuotationAskSuppliers', 'PurchaseRequest',
  18.     'CreatePurchaseRequestQuotation']
  19.  
  20. STATES = [
  21.     ('draft', 'Draft'),
  22.     ('sent', 'Sent'),
  23.     ('rejected', 'Rejected'),
  24.     ('answered', 'Answered'),
  25.     ('cancel', 'Canceled'),
  26.     ]
  27.  
  28.  
  29. class Configuration:
  30.     __metaclass__ = PoolMeta
  31.     __name__ = 'purchase.configuration'
  32.     purchase_request_quotation_group_sequence = fields.Property(
  33.         fields.Many2One(
  34.             'ir.sequence', 'Purchase Request Quotation Group Sequence',
  35.             domain=[
  36.                 ('company', 'in',
  37.                     [Eval('context', {}).get('company', -1), None]),
  38.                 ('code', '=', 'purchase.request.quotation.group'),
  39.                 ],
  40.             required=True))
  41.  
  42.  
  43. class Group(Workflow, ModelSQL, ModelView):
  44.     "Purchase Request For Quotation Group"
  45.     __name__ = 'purchase.request.quotation.group'
  46.     _rec_name = 'number'
  47.  
  48.     number = fields.Char('Number', required=True, readonly=True)
  49.     company = fields.Many2One('company.company', 'Company', required=True,
  50.         readonly=True, select=True, domain=[
  51.             ('id', If(Eval('context', {}).contains('company'), '=', '!='),
  52.                 Eval('context', {}).get('company', -1)),
  53.             ])
  54.     supplier = fields.Many2One('party.party', 'Supplier', required=True,
  55.         readonly=True, select=True)
  56.     request_quotations = fields.One2Many('purchase.request.quotation', 'group',
  57.         'Purchase Request For Quotation', readonly=True)
  58.     state = fields.Selection(STATES, 'State', readonly=True, required=True)
  59.  
  60.     @classmethod
  61.     def __setup__(cls):
  62.         super(Group, cls).__setup__()
  63.         cls._transitions |= set((
  64.                 ('draft', 'cancel'),
  65.                 ('cancel', 'draft'),
  66.                 ('draft', 'sent'),
  67.                 ('sent', 'rejected'),
  68.                 ('sent', 'answered'),
  69.                 ('answered', 'rejected'),
  70.                 ('rejected', 'answered'),
  71.                 ))
  72.         cls._buttons.update({
  73.                 'cancel': {
  74.                     'invisible': Eval('state') != 'draft',
  75.                     },
  76.                 'send': {
  77.                     'invisible': Eval('state') != 'draft',
  78.                     },
  79.                 'answer': {
  80.                     'invisible': ~Eval('state').in_(
  81.                         ['sent', 'rejected']),
  82.                     },
  83.                 'reject': {
  84.                     'invisible': ~Eval('state').in_(
  85.                         ['sent', 'answered']),
  86.                     },
  87.                 })
  88.  
  89.     @staticmethod
  90.     def default_company():
  91.         return Transaction().context.get('company')
  92.  
  93.     @staticmethod
  94.     def default_state():
  95.         return 'draft'
  96.  
  97.     @classmethod
  98.     def create(cls, vlist):
  99.         pool = Pool()
  100.         Sequence = pool.get('ir.sequence')
  101.         Config = pool.get('purchase.configuration')
  102.  
  103.         config = Config(1)
  104.         vlist = [v.copy() for v in vlist]
  105.         for values in vlist:
  106.             if values.get('number') is None:
  107.                 values['number'] = Sequence.get_id(
  108.                     config.purchase_request_quotation_group_sequence.id)
  109.         return super(Group, cls).create(vlist)
  110.  
  111.     @classmethod
  112.     def copy(cls, groups, default=None):
  113.         if default is None:
  114.             default = {}
  115.         else:
  116.             default = default.copy()
  117.         default.setdefault('request_quotations', None)
  118.         return super(Group, cls).copy(groups, default=default)
  119.  
  120.     @classmethod
  121.     @ModelView.button
  122.     @Workflow.transition('cancel')
  123.     def cancel(cls, quotations):
  124.         pass
  125.  
  126.     @classmethod
  127.     @Workflow.transition('draft')
  128.     def draft(cls, quotations):
  129.         pass
  130.  
  131.     @classmethod
  132.     @ModelView.button
  133.     @Workflow.transition('send')
  134.     def send(cls, quotations):
  135.         pass
  136.  
  137.     @classmethod
  138.     @ModelView.button
  139.     @Workflow.transition('answer')
  140.     def answer(cls, quotations):
  141.         pass
  142.  
  143.     @classmethod
  144.     @ModelView.button
  145.     @Workflow.transition('reject')
  146.     def reject(cls, quotations):
  147.         pass
  148.  
  149.  
  150. class PurchaseRequestQuotation(
  151.         sequence_ordered(), ModelSQL, ModelView):
  152.     "Purchase Request For Quotation"
  153.     __name__ = 'purchase.request.quotation'
  154.  
  155.     company = fields.Many2One('company.company', 'Company', required=True,
  156.         readonly=True,
  157.         domain=[
  158.             ('id', If(Eval('context', {}).contains('company'), '=', '!='),
  159.                 Eval('context', {}).get('company', -1)),
  160.             ], select=True)
  161.     supplier = fields.Many2One('party.party', 'Supplier', required=True,
  162.         readonly=True, select=True)
  163.     supply_date = fields.Date('Expected Supply Date')
  164.     product = fields.Function(fields.Many2One('product.product', 'Product'),
  165.         'get_product', searcher='search_product')
  166.     description = fields.Text('Description',
  167.         states={
  168.             'required': ~Eval('product')
  169.             },
  170.         depends=['product'])
  171.     quantity = fields.Float(
  172.         'Quantity', digits=(16, Eval('unit_digits', 2)), required=True,
  173.         depends=['unit_digits'])
  174.     unit = fields.Many2One(
  175.         'product.uom', 'Unit', ondelete='RESTRICT',
  176.         states={
  177.             'required': Bool(Eval('product')),
  178.             },
  179.         domain=[
  180.             If(Bool(Eval('product_uom_category')),
  181.                 ('category', '=', Eval('product_uom_category')),
  182.                 ('category', '!=', -1)),
  183.         ],
  184.         depends=['product', 'product_uom_category'])
  185.     unit_digits = fields.Function(
  186.         fields.Integer('Unit Digits'), 'on_change_with_unit_digits')
  187.     product_uom_category = fields.Function(
  188.         fields.Many2One('product.uom.category', 'Product Uom Category'),
  189.         'on_change_with_product_uom_category')
  190.     unit_price = fields.Numeric('Unit Price', digits=price_digits)
  191.     currency = fields.Many2One('currency.currency', 'Currency')
  192.     currency_digits = fields.Function(
  193.         fields.Integer('Currency Digits'), 'on_change_with_currency_digits')
  194.     amount = fields.Function(
  195.         fields.Numeric('Amount',
  196.             digits=(16, Eval('currency_digits', 2)),
  197.             depends=['currency_digits']), 'on_change_with_amount')
  198.     request = fields.Many2One('purchase.request', 'Request',
  199.         ondelete='CASCADE', select=True, required=True)
  200.     group = fields.Many2One('purchase.request.quotation.group', 'Group',
  201.         readonly=True,
  202.         ondelete='RESTRICT',
  203.         domain=[
  204.             ('company', '=', Eval('company', -1)),
  205.             ],
  206.         depends=['company'])
  207.     group_state = fields.Function(
  208.         fields.Selection(STATES, 'Request for Quotation Group State'),
  209.         'on_change_with_group_state')
  210.  
  211.     @fields.depends('group', '_parent_group.state')
  212.     def on_change_with_group_state(self, name=None):
  213.         if self.group:
  214.             return self.group.state
  215.  
  216.     @fields.depends('quantity', 'unit_price', 'unit', 'currency')
  217.     def on_change_with_amount(self, name=None):
  218.         if (self.unit_price is None) or (self.quantity is None):
  219.             return None
  220.         amount = Decimal(str(self.quantity)) * self.unit_price
  221.         if self.currency:
  222.             amount = self.currency.round(amount)
  223.         return amount
  224.  
  225.     @fields.depends('product')
  226.     def on_change_with_product_uom_category(self, name=None):
  227.         if self.product:
  228.             return self.product.default_uom_category.id
  229.  
  230.     @fields.depends('unit')
  231.     def on_change_with_unit_digits(self, name=None):
  232.         if self.unit:
  233.             return self.unit.digits
  234.         return 2
  235.  
  236.     @fields.depends('currency')
  237.     def on_change_with_currency_digits(self, name=None):
  238.         if self.currency:
  239.             return self.currency.digits
  240.         return 2
  241.  
  242.     def get_product(self, name):
  243.         if self.request and self.request.product:
  244.             return self.request.product.id
  245.  
  246.     @classmethod
  247.     def search_product(cls, name, clause):
  248.         return [('request.product',) + tuple(clause[1:])]
  249.  
  250.  
  251. class CreatePurchaseRequestQuotationAskSuppliers(ModelView):
  252.     'Create Purchase Request Quotation Ask Suppliers'
  253.     __name__ = 'purchase.request.create_quotation.ask_suppliers'
  254.  
  255.     requests = fields.Many2Many('purchase.request', None, None, 'Requests',
  256.                     required=True, readonly=True)
  257.     suppliers = fields.Many2Many('party.party', None, None, 'Suppliers',
  258.                     required=True)
  259.  
  260.  
  261. class CreatePurchaseRequestQuotation(Wizard):
  262.     'Create Purchase Request Quotation'
  263.     __name__ = 'purchase.request.create_quotation'
  264.  
  265.     start_state = 'ask_suppliers'
  266.     ask_suppliers = StateView(
  267.         'purchase.request.create_quotation.ask_suppliers',
  268.         'purchase_request_quotation.' +
  269.         'purchase_request_create_quotation_ask_suppliers', [
  270.             Button('Cancel', 'end', 'tryton-cancel'),
  271.             Button('Continue', 'start', 'tryton-go-next', default=True),
  272.             ])
  273.     start = StateTransition()
  274.  
  275.     @classmethod
  276.     def __setup__(cls):
  277.         super(CreatePurchaseRequestQuotation, cls).__setup__()
  278.         cls._error_messages.update({
  279.                 'previous_quotation': ('You already made a quotation with '
  280.                     'one of the selected requests: "%(requests)s".'),
  281.                 })
  282.  
  283.     def default_ask_suppliers(self, fields):
  284.         pool = Pool()
  285.         suppliers = []
  286.         request_quotation_state = []
  287.         Request = pool.get('purchase.request')
  288.  
  289.         request_ids = Transaction().context['active_ids']
  290.         requests = Request.search([
  291.                     ('id', 'in', request_ids),
  292.                     ('state', 'in', ['draft', 'quotation']),
  293.                     ])
  294.         for request in requests:
  295.             if request.state == 'quotation':
  296.                 request_quotation_state.append(request)
  297.             if request.party:
  298.                 suppliers.append(request.party.id)
  299.         if request_quotation_state:
  300.             self.raise_user_warning('warning', 'previous_quotation', {
  301.                             'requests': ', '.join(r.rec_name
  302.                                 for r in request_quotation_state),
  303.                             })
  304.         return {
  305.             'requests': [r.id for r in requests],
  306.             'suppliers': suppliers,
  307.             }
  308.  
  309.     def transition_start(self):
  310.         pool = Pool()
  311.         Request = pool.get('purchase.request')
  312.         Quotation = pool.get('purchase.request.quotation')
  313.  
  314.         new_quotations = []
  315.         request_ids = Transaction().context['active_ids']
  316.         requests = Request.search([
  317.                     ('id', 'in', request_ids),
  318.                     ('state', 'in', ['draft', 'quotation']),
  319.                     ])
  320.         for request in requests:
  321.             new_quotations.append({
  322.                         'company': request.company,
  323.                         'request': request,
  324.                         'description': request.description,
  325.                         'quantity': request.quantity,
  326.                         'unit': request.uom,
  327.                         'currency': request.currency,
  328.                         'supply_date': (
  329.                             request.supply_date or datetime.date.max),
  330.                         })
  331.         suppliers = []
  332.         for supplier in getattr(self.ask_suppliers, 'suppliers', []):
  333.             suppliers.append({
  334.                     'supplier': supplier,
  335.                     })
  336.         if suppliers:
  337.             quotation_lines = []
  338.             '''
  339.            Cartesian product between purchase_requests and suppliers
  340.            '''
  341.             for (nq, s) in product(new_quotations, suppliers):
  342.                 merged_dict = {}
  343.                 merged_dict.update(nq)
  344.                 merged_dict.update(s)
  345.                 quotation = Quotation()
  346.                 for f, v in merged_dict.iteritems():
  347.                     setattr(quotation, f, v)
  348.                 quotation_lines.append(quotation)
  349.  
  350.             Quotation.save(quotation_lines)
  351.  
  352.             quotations = sorted(quotation_lines,
  353.                             key=self._group_purchase_request_quotation_key)
  354.             for key, grouped_quotations in groupby(quotations,
  355.                     key=self._group_purchase_request_quotation_key):
  356.                     group = self._new_group(dict(key))
  357.                     grouped_quotations = list(grouped_quotations)
  358.                     group.save()
  359.                     Quotation.write(grouped_quotations, {'group': group.id})
  360.  
  361.         return 'end'
  362.  
  363.     def _group_purchase_request_quotation_key(self, quotation):
  364.         return (
  365.             ('company', quotation.company),
  366.             ('supplier', quotation.supplier),
  367.             )
  368.  
  369.     def _new_group(self, values):
  370.         pool = Pool()
  371.         Group = pool.get('purchase.request.quotation.group')
  372.         return Group(**values)
  373.  
  374.  
  375. class PurchaseRequest:
  376.     __metaclass__ = PoolMeta
  377.     __name__ = 'purchase.request'
  378.  
  379.     quotations = fields.One2Many('purchase.request.quotation',
  380.             'request', 'Quotations', readonly=True)
  381.  
  382.     @classmethod
  383.     def __setup__(cls):
  384.         super(PurchaseRequest, cls).__setup__()
  385.         selection = ('quotation', 'Quotation')
  386.         if selection not in cls.state.selection:
  387.             cls.state.selection.append(selection)
  388.  
  389.     def get_state(self, name):
  390.         state = super(PurchaseRequest, self).get_state(name)
  391.         if state == 'draft' and self.quotations:
  392.             state = 'quotation'
  393.         return state
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement