def __setup__(cls): super(Appointment, cls).__setup__() cls._error_messages.update( no_institution="No institution specified in appointment [%s]") cls.state.selection = APPOINTMENT_STATES cls._buttons.update({ 'start_encounter': { 'readonly': Not(And(Equal(Eval('state'), 'arrived'), Bool(Eval('name')))), 'invisible': In(Eval('state'), ['processing', 'done']), }, 'goto_encounter': { 'invisible': Not(In(Eval('state'), ['processing', 'done'])) }, 'client_arrived': { 'readonly': Not(And(Equal(Eval('state'), 'confirmed'), Bool(Eval('name')))) } }) ro_states = {'readonly': Not(In(Eval('state'), ['confirmed', 'free']))} cls.patient.states.update(ro_states) cls.institution.states = ro_states cls.state.states = ro_states cls.appointment_date.states = ro_states cls.comments.states.update( {'invisible': ~Eval('can_do_details', False)})
class BankAccount(metaclass=PoolMeta): __name__ = 'bank.account' journal = fields.Many2One('account.journal', 'Account Journal', states={ 'required': If( In(Eval('party_company'), Eval('owners', [])), True, False), }, depends=['owners', 'party_company']) credit_account = fields.Many2One( 'account.account', 'Credit Account', states={ 'required': If(In(Eval('party_company'), Eval('owners', [])), True, False), }, domain=[ ('kind', '!=', 'view'), ('company', '=', Eval('context', {}).get('company', -1)), ], depends=['owners', 'party_company']) debit_account = fields.Many2One( 'account.account', 'Debit Account', states={ 'required': If(In(Eval('party_company'), Eval('owners', [])), True, False), }, domain=[ ('kind', '!=', 'view'), ('company', '=', Eval('context', {}).get('company', -1)), ], depends=['owners', 'party_company']) party_company = fields.Function( fields.Many2One('party.party', 'party_company'), 'on_change_with_party_company') @staticmethod def default_party_company(): Company = Pool().get('company.company') if Transaction().context.get('company'): company = Company(Transaction().context['company']) return company.party.id def on_change_with_party_company(self, name=None): Company = Pool().get('company.company') if Transaction().context.get('company'): company = Company(Transaction().context['company']) return company.party.id def get_cbu_number(self): ''' Return cbu number ''' for account_number in self.numbers: if account_number.type == 'cbu': return account_number.number_compact
def __setup__(cls): super(AccountVoucher, cls).__setup__() cls._buttons.update({ 'transferir': { 'invisible': ~Eval('transfer', True), 'readonly': In(Eval('state'), ['posted']), }, }) cls._buttons.update({ 'post': { 'invisible': Eval('transfer', True), 'readonly': In(Eval('state'), ['posted']), }, }) del cls.party.states['required'] cls.party.states['required'] = ~Eval('transfer', True) cls.party.states['invisible'] = Eval('transfer', True) cls.voucher_type.states['invisible'] = Eval('transfer', True) cls.pay_lines.states['invisible'] = Eval('transfer', True) cls.lines.states['invisible'] = Eval('transfer', True) cls.lines_credits.states['invisible'] = Eval('transfer', True) cls.lines_debits.states['invisible'] = Eval('transfer', True) cls.amount.states['invisible'] = Eval('transfer', True) cls.amount_to_pay.states['invisible'] = Eval('transfer', True) cls.amount_invoices.states['invisible'] = Eval('transfer', True) cls.move.states['invisible'] = Eval('transfer', True) cls.from_pay_invoice.states['invisible'] = Eval('transfer', True) cls.amount_to_pay_words.states['invisible'] = Eval('transfer', True)
def __setup__(cls): super(ReceiptLine, cls).__setup__() cls.type.selection += [ ('advance_in_apply', 'Apply Collected in Advanced from Customer'), ('advance_in_create', 'Create Collected in Advance from Customer'), ('advance_out_apply', 'Apply Paid in Advanced to Supplier'), ('advance_out_create', 'Create Paid in Advance to Supplier'), ] cls.party.states['readonly'] = Or( Eval('receipt_state') != 'draft', Bool(Eval('invoice')), Bool(Eval('advance')), ) cls.party.depends += ['advance'] cls.account.states['readonly'] = Or( Eval('receipt_state') != 'draft', Not( In(Eval('type'), ['move_line', 'advance_in_create', 'advance_out_create'])), ) cls.account.domain.append( If(In(Eval('type'), ['advance_in_create', 'advance_out_create']), [('reconcile', '=', True), ('party_required', '=', True)], []))
def __setup__(cls): super(Move, cls).__setup__() for fname in ('package', 'number_of_packages'): if 'readonly' in getattr(cls, fname).states: getattr(cls, fname).states['readonly'] |= In( Eval('state'), ['cancel', 'assigned', 'done']) else: getattr(cls, fname).states['readonly'] = In( Eval('state'), ['cancel', 'assigned', 'done']) getattr(cls, fname).depends.append('state') cls._deny_modify_assigned |= set( ['number_of_packages', 'number_of_packages'])
def view_attributes(cls): return super(PaymentTransaction, cls).view_attributes() + [( '/tree', 'colors', If( In( Eval('state', ''), ['in-progress', 'authorized', 'completed'] ), 'blue', If( In(Eval('state', ''), ['failed', 'cancel']), 'red', If(Equal(Eval('state', ''), 'posted'), 'green', 'black') ) ) )]
def __setup__(cls): super(TriageEntry, cls).__setup__() cls._buttons.update({ 'set_done': { 'readonly': ~Eval('can_do_details', False), 'invisible': Or(In(Eval('status'), ['pending', 'triage']), Eval('done', False)) }, 'go_referral': { 'readonly': ~Eval('can_do_details', False), 'invisible': ~In(Eval('status'), ['refer', 'referin']) } })
class Party(metaclass=PoolMeta): __name__ = 'party.party' party_type = fields.Selection([ (None, ''), ('person', 'Person'), ('private', 'Private Organisation'), ('foundation', 'Foundation'), ('government', 'Government'), ], 'Type', states={ 'readonly': ~Eval('active', True), }, depends=['active']) dob = fields.Date('Date of Birth/Establishment') gender = fields.Selection( [ (None, ''), ('male', 'Male'), ('female', 'Female'), ], 'Gender', states={ 'readonly': ~Eval('active', True), 'invisible': Not(In(Eval('party_type'), ['person'])), }, depends=['party_type']) person_legal_state = fields.Selection( [ (None, ''), ('married', 'Married'), ('single', 'Single'), ('divorced', 'Divorced'), ('widow', 'Widow(er)'), ], 'Legal state', states={ 'readonly': ~Eval('active', True), 'invisible': Not(In(Eval('party_type'), ['person'])), }, depends=['party_type']) @classmethod def __setup__(cls): super(Party, cls).__setup__() cls.last_name.states['invisible'] = \ Not(In(Eval('party_type'), ['person'])) cls.last_name.depends += ['party_type']
def __setup__(cls): super(InpatientRegistration, cls).__setup__() # Make readonly for bed depends on a person being hospitalised or # discharged from the hospital cls.bed.states = {'required': True, 'readonly': Or(Equal(Eval('state'), 'hospitalized'), Equal(Eval('state'), 'confirmed'), Equal(Eval('state'), 'done'))} # Changed depends to accommodate state cls.bed.depends = ['name', 'state'] # make discharge_date not required cls.discharge_date.required = False if not cls.discharge_date.states: cls.discharge_date.states = {} cls.discharge_date.states['invisible'] = Not( In(Eval('state'), ['done', 'hospitalized'])) # rename the set of states cls.state.selection = [ ('free', 'Pending'), ('cancelled', 'Cancelled'), ('confirmed', 'Confirmed'), ('hospitalized', 'Admitted'), ('done', 'Discharged/Done') ] # discharge_date is the real thing cls.discharge_date.string = 'Discharged'
class Property(ModelSQL, ModelView): _name = 'ir.property' company = fields.Many2One('company.company', 'Company', domain=[ ('id', If(In('company', Eval('context', {})), '=', '!='), Get(Eval('context', {}), 'company', 0)), ]) def _set_values(self, name, model, res_id, val, field_id): user_obj = self.pool.get('res.user') user = user_obj.browse(Transaction().user) res = super(Property, self)._set_values(name, model, res_id, val, field_id) if user: res['company'] = user.company.id return res def search(self, domain, offset=0, limit=None, order=None, count=False): if Transaction().user == 0: domain = ['AND', domain[:], ('company', '=', False)] return super(Property, self).search(domain, offset=offset, limit=limit, order=order, count=count)
class Journal: __metaclass__ = PoolMeta __name__ = 'account.journal' sequences = fields.One2Many('account.journal.invoice.sequence', 'journal', 'Sequences', states={ 'invisible': Not(In(Eval('type'), ['revenue', 'expense'])), }) def get_invoice_sequence(self, invoice): pool = Pool() Date = pool.get('ir.date') date = invoice.invoice_date or Date.today() for sequence in self.sequences: period = sequence.period if period and (period.start_date <= date and period.end_date >= date): return getattr(sequence, invoice.type + '_sequence') for sequence in self.sequences: fiscalyear = sequence.fiscalyear if (fiscalyear.start_date <= date and fiscalyear.end_date >= date): return getattr(sequence, invoice.type + '_sequence') @classmethod def view_attributes(cls): return super(Journal, cls).view_attributes() + [ ('//page[@id="sequences"]', 'states', { 'invisible': Not(In(Eval('type'), ['revenue', 'expense'])), })]
class SaleOpportunity: 'Sale Oppotunity' __name__ = 'sale.opportunity' incoterms = fields.One2Many('sale.opportunity.incoterm', 'opportunity', 'Incoterm Sale Opportunity', states={ 'readonly': Not( In(Eval('state'), ['lead', 'opportunity'])), }, depends=['state']) def create_sale(self): ''' Create a sale for the opportunity and return the sale ''' SaleIncoterm = Pool().get('sale.incoterm') sale = super(SaleOpportunity, self).create_sale() SaleIncoterm.create( map( lambda incoterm: { 'year': incoterm.year, 'abbrevation': incoterm.abbrevation, 'value': incoterm.value, 'currency': incoterm.currency.id, 'city': incoterm.city, 'sale': sale.id, }, self.incoterms)) return sale
def __setup__(cls): super(Signature, cls).__setup__() cls._transitions |= set(( ('issued', 'ready'), ('issued', 'expired'), ('issued', 'canceled'), ('issued', 'failed'), ('issued', 'completed'), ('issued', 'pending_validation'), ('ready', 'expired'), ('ready', 'canceled'), ('ready', 'failed'), ('ready', 'completed'), ('ready', 'pending_validation'), ('pending_validation', 'expired'), ('pending_validation', 'canceled'), ('pending_validation', 'failed'), ('pending_validation', 'completed'), )) cls._buttons.update({ 'update_transaction_info': { 'invisible': Not( In(Eval('status'), ['', 'issued', 'ready', 'pending_validation'])) }, 'relaunch_transaction': { 'invisible': Eval('status') != 'ready' }, })
def __setup__(cls): super(Attachment, cls).__setup__() cls._buttons.update({ 'cryptolog_update_transaction_info': { 'invisible': Not(In(Eval('cryptolog_status'), ['', 'issued', 'ready'])) } })
class BankAccount(metaclass=PoolMeta): __name__ = 'bank.account' pyafipws_cbu = fields.Boolean('CBU del Emisor', states={ 'required': If( In(Eval('party_company'), Eval('owners', [])), True, False), }, depends=['owners', 'party_company'])
def __setup__(cls): super(Todo, cls).__setup__() cls._order = [ ('sequence', 'ASC'), ('create_date', 'DESC'), ('id', 'DESC'), ] cls._transitions |= set(( ('open', 'done'), ('done', 'open'), )) cls._buttons.update({ 'done': { 'invisible': In(Eval('state'), ['done']), }, 'open': { 'invisible': In(Eval('state'), ['open']), }, })
def __setup__(cls): super(PatientEncounter, cls).__setup__() cls._error_messages.update({ 'health_professional_warning': 'No health professional ' 'associated with this user', 'end_date_before_start': 'End time cannot be before' 'Start time\n"%(start_time)s"', 'end_date_required': 'End time is required for finishing', 'unsigned_components': 'There are unsigned components.' # 'This encounter cannot be signed' }) cls._buttons.update({ 'set_done': { 'invisible': Not(Equal(Eval('state'), 'in_progress')), 'readonly': Or(Greater(0, Eval('id', -1)), Greater(1, Len(Eval('components')))) }, 'sign_finish': { 'invisible': Not(Equal(Eval('state'), 'done')) }, 'add_component': { 'readonly': Or(Greater(0, Eval('id', -1)), In(Eval('state'), ['done', 'signed', 'invalid'])), 'invisible': Equal(Eval('state'), 'signed') }, 'add_extra_component': { 'invisible': In(Eval('state'), ['signed', 'in_progress', 'invalid']) } })
class Move(metaclass=PoolMeta): __name__ = 'stock.move' fraction = fields.Many2One( 'lims.fraction', 'Fraction', select=True, ondelete='CASCADE', states={ 'readonly': (In(Eval('state'), ['cancel', 'assigned', 'done']) | Bool(Eval('fraction_readonly'))) }, domain=[ If(~Eval('fraction'), ('current_location', '=', Eval('from_location')), ('id', '=', Eval('fraction'))), ], depends=['state', 'fraction_readonly', 'from_location']) fraction_readonly = fields.Function(fields.Boolean('Fraction Read Only'), 'on_change_with_fraction_readonly') @classmethod def __setup__(cls): super().__setup__() cls.origin.readonly = True @classmethod def _get_origin(cls): models = super()._get_origin() models.append('lims.fraction') return models @fields.depends('from_location', 'to_location', 'product') def on_change_with_fraction_readonly(self, name=None): Config = Pool().get('lims.configuration') config = Config(1) if not config.fraction_product: return True if not self.product or self.product != config.fraction_product: return True if (self.from_location and self.to_location and self.from_location.type == 'storage' and self.to_location.type == 'storage'): return False return True @classmethod def copy(cls, moves, default=None): with Transaction().set_context(check_current_location=False): return super().copy(moves, default=default)
class InvoiceLine(ModelSQL, ModelView): """Invoice Line""" _name = 'account.invoice.line' work = fields.Many2One('timesheet.work', 'Work') timesheet_lines = fields.One2Many( 'timesheet.line', 'invoice_line', 'Timesheet Lines', add_remove=[ ('invoice_line', '=', False), ('work', '=', Eval('work')), ('billable', '=', True), ('hours', '>', 0), ], ) # add timesheet_lines to on_change_with list on parent quantity = fields.Float('Quantity', digits=(16, Eval('unit_digits', 2)), states={ 'invisible': Not(Equal(Eval('type'), 'line')), 'required': Equal(Eval('type'), 'line'), }, on_change_with=['timesheet_lines']) # add timesheet_lines to on_change_with list on parent amount = fields.Function( fields.Numeric('Amount', digits=(16, Get(Eval('_parent_invoice', {}), 'currency_digits', Eval('currency_digits', 2))), states={ 'invisible': Not(In(Eval('type'), ['line', 'subtotal'])), }, on_change_with=[ 'type', 'quantity', 'unit_price', '_parent_invoice.currency', 'currency', 'timesheet_lines', ]), 'get_amount') def on_change_with_quantity(self, vals): hours = 0.0 for line in vals.get('timesheet_lines'): hours = hours + line.get('hours') return hours
class Sequence(ModelSQL, ModelView): _name = 'ir.sequence' company = fields.Many2One('company.company', 'Company', domain=[ ('id', If(In('company', Eval('context', {})), '=', '!='), Get(Eval('context', {}), 'company', 0)), ]) def __init__(self): super(Sequence, self).__init__() self._order.insert(0, ('company', 'ASC')) def default_company(self): return Transaction().context.get('company') or False
conversor = None try: from numword import numword_es conversor = numword_es.NumWordES() except: print("Warning: Does not possible import numword module!") print("Please install it...!") __all__ = [ 'AccountVoucherSequence', 'AccountVoucherPayMode', 'AccountVoucher', 'AccountVoucherLine', 'AccountVoucherLineCredits', 'AccountVoucherLineDebits', 'AccountVoucherLinePaymode', 'VoucherReport' ] _STATES = { 'readonly': In(Eval('state'), ['posted']), } class AccountVoucherSequence(ModelSingleton, ModelSQL, ModelView): 'Account Voucher Sequence' __name__ = 'account.voucher.sequence' voucher_payment_sequence = fields.Property( fields.Many2One('ir.sequence', 'Voucher Payment Sequence', required=True, domain=[ ('code', '=', 'account.voucher.payment'), ('company', 'in', [Eval('context', {}).get('company'), None]),
from trytond.model import ModelView, ModelSQL, fields from trytond.pyson import Eval, Not, Bool, PYSONEncoder, Equal, And, Or, In from trytond.pool import Pool _Jamaica_instance = False def JAMAICA(): global _Jamaica_instance if not _Jamaica_instance: _Jamaica_instance, = Pool().get('country.country').search([('code','=', 'JM')]) return _Jamaica_instance JAMAICA_ID = 89 INVISIBLEJM = {'invisible':In(Eval('address_country'), [JAMAICA_ID])} VISIBLEJM = {'invisible':Not(In(Eval('address_country'), [JAMAICA_ID]))} class DomiciliaryUnit(ModelSQL, ModelView): 'Domiciliary Unit' __name__ = 'gnuhealth.du' address_street_num = fields.Char('Street Number', size=8) address_post_office = fields.Many2One( 'country.post_office', 'Post Office (JM)', help="Closest Post Office, Jamaica only", domain=[('subdivision', '=', Eval('address_subdivision'))], depends=['address_subdivision'], states=VISIBLEJM) address_district_community = fields.Many2One(
class SaleOpportunity(Workflow, ModelSQL, ModelView): 'Sale Opportunity' __name__ = "sale.opportunity" _history = True _rec_name = 'number' number = fields.Char('Number', readonly=True, required=True, select=True) reference = fields.Char('Reference', select=True) party = fields.Many2One( 'party.party', 'Party', select=True, states={ 'readonly': Eval('state').in_(['converted', 'lost', 'cancelled']), 'required': ~Eval('state').in_(['lead', 'lost', 'cancelled']), }, depends=['state']) address = fields.Many2One('party.address', 'Address', domain=[('party', '=', Eval('party'))], select=True, depends=['party', 'state'], states=_STATES_STOP) company = fields.Many2One('company.company', 'Company', required=True, select=True, states=_STATES_STOP, domain=[ ('id', If(In('company', Eval('context', {})), '=', '!='), Get(Eval('context', {}), 'company', 0)), ], depends=_DEPENDS_STOP) currency = fields.Function( fields.Many2One('currency.currency', 'Currency'), 'get_currency') currency_digits = fields.Function(fields.Integer('Currency Digits'), 'get_currency_digits') amount = fields.Numeric('Amount', digits=(16, Eval('currency_digits', 2)), states=_STATES_STOP, depends=_DEPENDS_STOP + ['currency_digits'], help='Estimated revenue amount') payment_term = fields.Many2One('account.invoice.payment_term', 'Payment Term', states={ 'readonly': In(Eval('state'), ['converted', 'lost', 'cancelled']), }, depends=['state']) employee = fields.Many2One( 'company.employee', 'Employee', states={ 'readonly': _STATES_STOP['readonly'], 'required': ~Eval('state').in_(['lead', 'lost', 'cancelled']), }, depends=['state', 'company'], domain=[('company', '=', Eval('company'))]) start_date = fields.Date('Start Date', required=True, select=True, states=_STATES_START, depends=_DEPENDS_START) end_date = fields.Date('End Date', select=True, states=_STATES_STOP, depends=_DEPENDS_STOP) description = fields.Char('Description', required=True, states=_STATES_STOP, depends=_DEPENDS_STOP) comment = fields.Text('Comment', states=_STATES_STOP, depends=_DEPENDS_STOP) lines = fields.One2Many('sale.opportunity.line', 'opportunity', 'Lines', states=_STATES_STOP, depends=_DEPENDS_STOP) state = fields.Selection(STATES, 'State', required=True, select=True, sort=False, readonly=True) conversion_probability = fields.Float( 'Conversion Probability', digits=(1, 4), required=True, domain=[ ('conversion_probability', '>=', 0), ('conversion_probability', '<=', 1), ], states={ 'readonly': ~Eval('state').in_(['opportunity', 'lead', 'converted']), }, depends=['state'], help="Percentage between 0 and 100") lost_reason = fields.Text('Reason for loss', states={ 'invisible': Eval('state') != 'lost', }, depends=['state']) sales = fields.One2Many('sale.sale', 'origin', 'Sales') @classmethod def __register__(cls, module_name): pool = Pool() Sale = pool.get('sale.sale') cursor = Transaction().connection.cursor() sql_table = cls.__table__() sale = Sale.__table__() table = cls.__table_handler__(module_name) number_exists = table.column_exist('number') # Migration from 3.8: rename reference into number if table.column_exist('reference') and not number_exists: table.column_rename('reference', 'number') number_exists = True super(SaleOpportunity, cls).__register__(module_name) table = cls.__table_handler__(module_name) # Migration from 3.4: replace sale by origin if table.column_exist('sale'): cursor.execute(*sql_table.select( sql_table.id, sql_table.sale, where=sql_table.sale != Null)) for id_, sale_id in cursor.fetchall(): cursor.execute( *sale.update(columns=[sale.origin], values=['%s,%s' % (cls.__name__, id_)], where=sale.id == sale_id)) table.drop_column('sale') # Migration from 4.0: change probability into conversion probability if table.column_exist('probability'): cursor.execute( *sql_table.update([sql_table.conversion_probability], [sql_table.probability / 100.0])) table.drop_constraint('check_percentage') table.drop_column('probability') # Migration from 4.2: make employee not required table.not_null_action('employee', action='remove') @classmethod def __setup__(cls): super(SaleOpportunity, cls).__setup__() cls._order.insert(0, ('start_date', 'DESC')) cls._error_messages.update({ 'delete_cancel': ('Sale Opportunity "%s" must be cancelled ' 'before deletion.'), }) cls._transitions |= set(( ('lead', 'opportunity'), ('lead', 'lost'), ('lead', 'cancelled'), ('lead', 'converted'), ('opportunity', 'converted'), ('opportunity', 'lead'), ('opportunity', 'lost'), ('opportunity', 'cancelled'), ('converted', 'won'), ('converted', 'lost'), ('won', 'converted'), ('lost', 'converted'), ('lost', 'lead'), ('cancelled', 'lead'), )) cls._buttons.update({ 'lead': { 'invisible': ~Eval('state').in_(['cancelled', 'lost', 'opportunity']), 'icon': If( Eval('state').in_(['cancelled', 'lost']), 'tryton-undo', 'tryton-back'), 'depends': ['state'], }, 'opportunity': { 'invisible': ~Eval('state').in_(['lead']), 'depends': ['state'], }, 'convert': { 'invisible': ~Eval('state').in_(['opportunity']), 'depends': ['state'], }, 'lost': { 'invisible': ~Eval('state').in_(['lead', 'opportunity']), 'depends': ['state'], }, 'cancel': { 'invisible': ~Eval('state').in_(['lead', 'opportunity']), 'depends': ['state'], }, }) @staticmethod def default_state(): return 'lead' @staticmethod def default_start_date(): Date = Pool().get('ir.date') return Date.today() @staticmethod def default_conversion_probability(): return 0.5 @staticmethod def default_company(): return Transaction().context.get('company') @staticmethod def default_employee(): return Transaction().context.get('employee') @classmethod def default_payment_term(cls): PaymentTerm = Pool().get('account.invoice.payment_term') payment_terms = PaymentTerm.search(cls.payment_term.domain) if len(payment_terms) == 1: return payment_terms[0].id @classmethod def create(cls, vlist): pool = Pool() Sequence = pool.get('ir.sequence') Config = pool.get('sale.configuration') config = Config(1) vlist = [x.copy() for x in vlist] for vals in vlist: if vals.get('number') is None: vals['number'] = Sequence.get_id( config.sale_opportunity_sequence.id) return super(SaleOpportunity, cls).create(vlist) @classmethod def copy(cls, opportunities, default=None): if default is None: default = {} else: default = default.copy() default.setdefault('number', None) default.setdefault('sales', None) return super(SaleOpportunity, cls).copy(opportunities, default=default) def get_currency(self, name): return self.company.currency.id def get_currency_digits(self, name): return self.company.currency.digits @fields.depends('company') def on_change_company(self): if self.company: self.currency = self.company.currency self.currency_digits = self.company.currency.digits @fields.depends('party') def on_change_party(self): if self.party and self.party.customer_payment_term: self.payment_term = self.party.customer_payment_term else: self.payment_term = self.default_payment_term() def _get_sale_opportunity(self): ''' Return sale for an opportunity ''' Sale = Pool().get('sale.sale') return Sale( description=self.description, party=self.party, payment_term=self.payment_term, company=self.company, invoice_address=self.address, shipment_address=self.address, currency=self.company.currency, comment=self.comment, sale_date=None, origin=self, warehouse=Sale.default_warehouse(), ) def create_sale(self): ''' Create a sale for the opportunity and return the sale ''' sale = self._get_sale_opportunity() sale_lines = [] for line in self.lines: sale_lines.append(line.get_sale_line(sale)) sale.lines = sale_lines return sale @classmethod def delete(cls, opportunities): # Cancel before delete cls.cancel(opportunities) for opportunity in opportunities: if opportunity.state != 'cancelled': cls.raise_user_error('delete_cancel', opportunity.rec_name) super(SaleOpportunity, cls).delete(opportunities) @classmethod @ModelView.button @Workflow.transition('lead') def lead(cls, opportunities): pass @classmethod @ModelView.button @Workflow.transition('opportunity') def opportunity(cls, opportunities): pass @classmethod @ModelView.button @Workflow.transition('converted') def convert(cls, opportunities): pool = Pool() Sale = pool.get('sale.sale') sales = [o.create_sale() for o in opportunities if not o.sales] Sale.save(sales) @property def is_forecast(self): pool = Pool() Date = pool.get('ir.date') today = Date.today() return self.end_date or datetime.date.max > today @classmethod @Workflow.transition('won') def won(cls, opportunities): pool = Pool() Date = pool.get('ir.date') cls.write([o for o in opportunities if o.is_forecast], { 'end_date': Date.today(), 'state': 'won', }) @classmethod @ModelView.button @Workflow.transition('lost') def lost(cls, opportunities): Date = Pool().get('ir.date') cls.write([o for o in opportunities if o.is_forecast], { 'end_date': Date.today(), 'state': 'lost', }) @classmethod @ModelView.button @Workflow.transition('cancelled') def cancel(cls, opportunities): Date = Pool().get('ir.date') cls.write([o for o in opportunities if o.is_forecast], { 'end_date': Date.today(), }) @staticmethod def _sale_won_states(): return ['confirmed', 'processing', 'done'] @staticmethod def _sale_lost_states(): return ['cancel'] def is_won(self): sale_won_states = self._sale_won_states() sale_lost_states = self._sale_lost_states() end_states = sale_won_states + sale_lost_states return (self.sales and all(s.state in end_states for s in self.sales) and any(s.state in sale_won_states for s in self.sales)) def is_lost(self): sale_lost_states = self._sale_lost_states() return (self.sales and all(s.state in sale_lost_states for s in self.sales)) @property def sale_amount(self): pool = Pool() Currency = pool.get('currency.currency') if not self.sales: return sale_lost_states = self._sale_lost_states() amount = 0 for sale in self.sales: if sale.state not in sale_lost_states: amount += Currency.compute(sale.currency, sale.untaxed_amount, self.currency) return amount @classmethod def process(cls, opportunities): won = [] lost = [] converted = [] for opportunity in opportunities: sale_amount = opportunity.sale_amount if opportunity.amount != sale_amount: opportunity.amount = sale_amount if opportunity.is_won(): won.append(opportunity) elif opportunity.is_lost(): lost.append(opportunity) elif (opportunity.state != 'converted' and opportunity.sales): converted.append(opportunity) cls.save(opportunities) if won: cls.won(won) if lost: cls.lost(lost) if converted: cls.convert(converted)
] STATES = [ ('lead', 'Lead'), ('opportunity', 'Opportunity'), ('converted', 'Converted'), ('won', 'Won'), ('cancelled', 'Cancelled'), ('lost', 'Lost'), ] _STATES_START = { 'readonly': Eval('state') != 'lead', } _DEPENDS_START = ['state'] _STATES_STOP = { 'readonly': In(Eval('state'), ['converted', 'won', 'lost', 'cancelled']), } _DEPENDS_STOP = ['state'] class SaleOpportunity(Workflow, ModelSQL, ModelView): 'Sale Opportunity' __name__ = "sale.opportunity" _history = True _rec_name = 'number' number = fields.Char('Number', readonly=True, required=True, select=True) reference = fields.Char('Reference', select=True) party = fields.Many2One( 'party.party', 'Party', select=True,
class AccountVoucher(metaclass=PoolMeta): __name__ = 'account.voucher' issued_check = fields.One2Many( 'account.issued.check', 'voucher', 'Issued Checks', add_remove=[ ('state', '=', 'draft'), ], states={ 'invisible': Not(In(Eval('voucher_type'), ['payment'])), 'readonly': Or(In(Eval('state'), ['posted']), Not(In(Eval('currency_code'), ['ARS']))), }) third_pay_checks = fields.Many2Many( 'account.voucher-account.third.check', 'voucher', 'third_check', 'Third Checks', states={ 'invisible': Not(In(Eval('voucher_type'), ['payment'])), 'readonly': Or(In(Eval('state'), ['posted']), Not(In(Eval('currency_code'), ['ARS']))), }, domain=[ ('state', '=', 'held'), ('not_to_order', '=', False), ]) third_check = fields.One2Many( 'account.third.check', 'voucher_in', 'Third Checks', add_remove=[ ('state', '=', 'draft'), ], states={ 'invisible': Not(In(Eval('voucher_type'), ['receipt'])), 'readonly': Or(In(Eval('state'), ['posted']), Not(In(Eval('currency_code'), ['ARS']))), }) @classmethod def __setup__(cls): super(AccountVoucher, cls).__setup__() cls._error_messages.update({ 'no_journal_check_account': 'You need to define a check account ' 'in the journal "%s",', 'check_not_in_draft': 'Check "%s" is not in draft state', 'issued_check_not_issued': ('Issued check "%s" is not in ' 'Issued state'), 'third_check_not_held': 'Third check "%s" is not in Held state', 'third_pay_check_not_delivered': ('Third check "%s" is not in ' 'Delivered state'), }) @fields.depends('party', 'pay_lines', 'lines_credits', 'lines_debits', 'issued_check', 'third_check', 'third_pay_checks') def on_change_with_amount(self, name=None): amount = super(AccountVoucher, self).on_change_with_amount(name) if self.third_check: for t_check in self.third_check: amount += t_check.amount if self.issued_check: for i_check in self.issued_check: amount += i_check.amount if self.third_pay_checks: for check in self.third_pay_checks: amount += check.amount return amount def prepare_move_lines(self): move_lines = super(AccountVoucher, self).prepare_move_lines() Period = Pool().get('account.period') if self.voucher_type == 'receipt': if self.third_check: if not self.journal.third_check_account: self.raise_user_error('no_journal_check_account', error_args=(self.journal.name, )) for check in self.third_check: if check.state != 'draft': self.raise_user_error('check_not_in_draft', error_args=(check.name, )) move_lines.append({ 'debit': check.amount, 'credit': _ZERO, 'account': self.journal.third_check_account.id, 'move': self.move.id, 'journal': self.journal.id, 'period': Period.find(self.company.id, date=self.date), 'party': (self.journal.third_check_account.party_required and self.party.id or None), 'maturity_date': check.date, }) if self.voucher_type == 'payment': if self.issued_check: if not self.journal.issued_check_account: self.raise_user_error('no_journal_check_account', error_args=(self.journal.name, )) for check in self.issued_check: move_lines.append({ 'debit': _ZERO, 'credit': check.amount, 'account': self.journal.issued_check_account.id, 'move': self.move.id, 'journal': self.journal.id, 'period': Period.find(self.company.id, date=self.date), 'party': (self.journal.issued_check_account.party_required and self.party.id or None), 'maturity_date': check.date, }) if self.third_pay_checks: for check in self.third_pay_checks: move_lines.append({ 'debit': _ZERO, 'credit': check.amount, 'account': self.journal.third_check_account.id, 'move': self.move.id, 'journal': self.journal.id, 'period': Period.find(self.company.id, date=self.date), 'party': (self.journal.third_check_account.party_required and self.party.id or None), 'maturity_date': check.date, }) return move_lines @classmethod @ModelView.button def post(cls, vouchers): pool = Pool() ThirdCheck = pool.get('account.third.check') IssuedCheck = pool.get('account.issued.check') Date = pool.get('ir.date') super(AccountVoucher, cls).post(vouchers) today = Date.today() for voucher in vouchers: if voucher.issued_check: IssuedCheck.write(list(voucher.issued_check), { 'receiving_party': voucher.party.id, 'state': 'issued', }) IssuedCheck.issued(voucher.issued_check) if voucher.third_check: ThirdCheck.write(list(voucher.third_check), { 'source_party': voucher.party.id, 'state': 'held', }) if voucher.third_pay_checks: ThirdCheck.write( list(voucher.third_pay_checks), { 'destiny_party': voucher.party.id, 'date_out': today, 'state': 'delivered', }) @classmethod @ModelView.button def cancel(cls, vouchers): pool = Pool() ThirdCheck = pool.get('account.third.check') IssuedCheck = pool.get('account.issued.check') super(AccountVoucher, cls).cancel(vouchers) for voucher in vouchers: if voucher.issued_check: for check in voucher.issued_check: if check.state != 'issued': cls.raise_user_error('issued_check_not_issued', (check.name, )) IssuedCheck.write(list(voucher.issued_check), { 'receiving_party': None, 'state': 'draft', }) if voucher.third_check: for check in voucher.third_check: if check.state != 'held': cls.raise_user_error('third_check_not_held', (check.name, )) ThirdCheck.write(list(voucher.third_check), { 'source_party': None, 'state': 'draft', }) if voucher.third_pay_checks: for check in voucher.third_pay_checks: if check.state != 'delivered': cls.raise_user_error('third_pay_check_not_delivered', (check.name, )) ThirdCheck.write(list(voucher.third_pay_checks), { 'destiny_party': None, 'date_out': None, 'state': 'held', })
class ReceiptLine(metaclass=PoolMeta): __name__ = 'cash_bank.receipt.line' advance = fields.Many2One( 'cash_bank.advance', 'Advance', domain=[ If( In(Eval('type'), [ 'advance_in_apply', 'advance_in_create', 'advance_out_apply', 'advance_out_create' ]), If(In(Eval('type'), ['advance_in_apply', 'advance_out_apply']), [('company', '=', Eval('_parent_receipt', {}).get( 'company', -1)), ('state', '=', 'pending'), ('currency', '=', Eval('_parent_receipt', {}).get( 'currency', -1)), ('party', '=', Eval('party')), If( Eval('type') == 'advance_in_apply', ('type', '=', 'in'), ('type', '=', 'out'))], [('id', '!=', -1)]), [('id', '=', -1)], ), ], states={ 'readonly': Eval('receipt_state') != 'draft', 'invisible': Not(In(Eval('type'), ['advance_in_apply', 'advance_out_apply'])) }, depends=['receipt_state', 'party', 'account', 'type']) advance_origin = fields.Reference( 'Origin', selection='get_advance_origin', states={ 'readonly': Eval('receipt_state') != 'draft', 'invisible': Not(In(Eval('type'), ['advance_in_create', 'advance_out_create'])) }, depends=['receipt_state', 'type']) @classmethod def __setup__(cls): super(ReceiptLine, cls).__setup__() cls.type.selection += [ ('advance_in_apply', 'Apply Collected in Advanced from Customer'), ('advance_in_create', 'Create Collected in Advance from Customer'), ('advance_out_apply', 'Apply Paid in Advanced to Supplier'), ('advance_out_create', 'Create Paid in Advance to Supplier'), ] cls.party.states['readonly'] = Or( Eval('receipt_state') != 'draft', Bool(Eval('invoice')), Bool(Eval('advance')), ) cls.party.depends += ['advance'] cls.account.states['readonly'] = Or( Eval('receipt_state') != 'draft', Not( In(Eval('type'), ['move_line', 'advance_in_create', 'advance_out_create'])), ) cls.account.domain.append( If(In(Eval('type'), ['advance_in_create', 'advance_out_create']), [('reconcile', '=', True), ('party_required', '=', True)], [])) @classmethod def get_advance_origin(cls): pool = Pool() Model = pool.get('ir.model') Advance = pool.get('cash_bank.advance') models = Advance._get_origin() models = Model.search([ ('model', 'in', models), ]) return [('', '')] + [(m.model, m.name) for m in models] @fields.depends('party', 'type') def on_change_party(self): pool = Pool() Config = pool.get('cash_bank.configuration') if self.party and self.type and \ self.type in ['advance_in_create', 'advance_out_create']: config = Config(1) if self.type == 'advance_in_create': self.account = config.default_collected_in_advanced_account else: self.account = config.default_paid_in_advanced_account @fields.depends('type') def on_change_type(self): super(ReceiptLine, self).on_change_type() self.advance = None self.advance_origin = None @fields.depends('advance', 'receipt', '_parent_receipt.type') def on_change_advance(self): if self.advance: self.amount = self.advance.amount_to_apply self.account = self.advance.receipt_line.account if self.receipt: if self.receipt.type.type == 'in': if self.advance.type == 'in': self.amount *= -1 else: if self.advance.type == 'out': self.amount *= -1 def validate_line(self): super(ReceiptLine, self).validate_line() pool = Pool() Currency = pool.get('currency.currency') if self.advance: with Transaction().set_context(date=self.advance.date): amount_to_apply = Currency.compute( self.advance.currency, self.advance.amount_to_apply, self.receipt.currency) if self.receipt.type.type == 'in': if self.advance.type == 'in' and \ self.type == 'advance_in_create': amount_to_apply = 1 elif self.advance.type == 'in' and \ self.type == 'advance_out_create': amount_to_apply = -1 elif self.advance.type == 'in' and \ self.type == 'advance_in_apply': amount_to_apply *= -1 elif self.advance.type == 'out' and \ self.type == 'advance_out_create': amount_to_apply = -1 else: if self.advance.type == 'out' and \ self.type == 'advance_out_create': amount_to_apply = 1 elif self.advance.type == 'out' and \ self.type == 'advance_in_create': amount_to_apply = -1 elif self.advance.type == 'out' and \ self.type == 'advance_out_apply': amount_to_apply *= -1 elif self.advance.type == 'in' and \ self.type == 'advance_in_create': amount_to_apply = -1 check_greater = True if self.type in \ ['advance_in_create', 'advance_out_create']: check_greater = False self._check_invalid_amount(amount_to_apply, self.advance.rec_name, check_greater=check_greater) def reconcile(self): super(ReceiptLine, self).reconcile() pool = Pool() Currency = pool.get('currency.currency') AdvanceLine = pool.get('cash_bank.advance.line_applied') MoveLine = pool.get('account.move.line') if self.advance: if self.type in \ ['advance_in_create', 'advance_out_create']: return with Transaction().set_context(date=self.advance.date): amount = Currency.compute(self.receipt.currency, self.amount, self.receipt.company.currency) amount_to_reconcile = abs(amount) reconcile_lines, remainder = \ self.advance.get_reconcile_lines_for_amount( amount_to_reconcile) line_applied = AdvanceLine(advance=self.advance, receipt_line=self) line_applied.save() if remainder == 0: lines = reconcile_lines + [self.line_move] MoveLine.reconcile(lines) self.advance.state = 'applied' self.advance.save()
class PatientEncounter(ModelSQL, ModelView): 'Patient Encounter' __name__ = 'gnuhealth.encounter' STATES = {'readonly': In(Eval('state'), ['signed', 'done', 'invalid'])} SIGNED_STATES = {'readonly': Equal(Eval('state'), 'signed')} SIGNED_VISIBLE = {'invisible': Not(Equal(Eval('state'), 'signed'))} active = fields.Boolean('Active', select=True) state = fields.Selection( [('in_progress', 'In progress'), ('done', 'Done'), ('signed', 'Signed'), ('invalid', 'Invalid')], 'State', readonly=True, sort=False, states={'invisible': Equal(Eval('state'), 'signed')}) patient = fields.Many2One('gnuhealth.patient', 'Patient', required=True, states={'readonly': Eval('id', 0) > 0}) primary_complaint = fields.Char('Primary complaint', states=STATES) start_time = fields.DateTime('Start', required=True, states=STATES) end_time = fields.DateTime('End', states=STATES) institution = fields.Many2One('gnuhealth.institution', 'Institution', required=True, states=STATES) appointment = fields.Many2One( 'gnuhealth.appointment', 'Appointment', domain=[('patient', '=', Eval('patient'))], depends=['patient'], help='Enter or select the appointment related to this encounter', states=STATES) next_appointment = fields.Many2One( 'gnuhealth.appointment', 'Next Appointment', # domain=['OR', ('state', '=', 'free'), # ('patient', '=', Eval('patient'))], depends=['patient'], states=SIGNED_STATES) signed_by = fields.Many2One( 'gnuhealth.healthprofessional', 'Signed By', readonly=True, states=SIGNED_VISIBLE, help="Health Professional that finished the patient evaluation") sign_time = fields.DateTime('Sign time', readonly=True, states=SIGNED_VISIBLE) components = fields.One2Many('gnuhealth.encounter.component', 'encounter', 'Components') summary = fields.Function(fields.Text('Summary'), 'get_encounter_summary') short_summary = fields.Function(fields.Text('Summary'), 'get_short_summary') # Patient identifier fields upi = fields.Function(fields.Char('UPI'), 'get_upi_mrn') medical_record_num = fields.Function(fields.Char('Medical Record Number'), 'get_upi_mrn') sex_display = fields.Function(fields.Char('Sex'), 'get_person_patient_field') age = fields.Function(fields.Char('Age', help="Age at start of encounter"), 'get_patient_age') crypto_enabled = fields.Function(fields.Boolean('Crypto Enabled'), 'get_crypto_enabled') clinicians = fields.Function(fields.One2Many( 'gnuhealth.healthprofessional', 'encounter', 'Clinicians'), 'get_clinicians', searcher='search_clinicians') @classmethod def __setup__(cls): super(PatientEncounter, cls).__setup__() cls._error_messages.update({ 'health_professional_warning': 'No health professional ' 'associated with this user', 'end_date_before_start': 'End time cannot be before' 'Start time\n"%(start_time)s"', 'end_date_required': 'End time is required for finishing', 'unsigned_components': 'There are unsigned components.' # 'This encounter cannot be signed' }) cls._buttons.update({ 'set_done': { 'invisible': Not(Equal(Eval('state'), 'in_progress')), 'readonly': Or(Greater(0, Eval('id', -1)), Greater(1, Len(Eval('components')))) }, 'sign_finish': { 'invisible': Not(Equal(Eval('state'), 'done')) }, 'add_component': { 'readonly': Or(Greater(0, Eval('id', -1)), In(Eval('state'), ['done', 'signed', 'invalid'])), 'invisible': Equal(Eval('state'), 'signed') }, 'add_extra_component': { 'invisible': In(Eval('state'), ['signed', 'in_progress', 'invalid']) } }) @classmethod def create(cls, vlist): ''' update appointment, set state = processing when encounter is first saved ''' retval = super(PatientEncounter, cls).create(vlist) Appointment = Pool().get('gnuhealth.appointment') appointments = [] for encounter in vlist: if encounter['appointment'] and not encounter.get('end_time'): appointments.append(encounter['appointment']) appts = Appointment.browse(appointments) Appointment.write(appts, {'state': 'processing'}) return retval @classmethod def validate(cls, records): for e in records: # 1. that the end-date is not before the start date if e.end_time and e.end_time <= e.start_time: cls.raise_user_error( 'end_date_before_start', { 'start_time': e.start_time.strftime('%c'), 'end_time': e.end_time.strftime('%c') }) # 2. That the encounter didn't start before the appointment # should we really though? return super(PatientEncounter, cls).validate(records) @classmethod @ModelView.button def sign_finish(cls, encounters): signing_hp = HealthProfessional().get_health_professional() if not signing_hp: cls.raise_user_error('health_professional_warning') #ToDO: set all the not-done components to DONE as well and sign # the unsigned ones # No! Components should be individually signed. for encounter in encounters: for comp in encounter.components: if not comp.signed_by: cls.raise_user_error('unsigned_components') cls.write( encounters, { 'state': 'signed', 'signed_by': signing_hp, 'sign_time': datetime.now() }) @classmethod @ModelView.button def set_done(cls, encounters): # Change the state of the evaluation to "Done" save_data = {'state': 'done'} appointments = [] # appointments to be set to done for encounter in encounters: if not encounter.end_time: cls.raise_user_warning( 'encounter_end_date_warn', 'End time has not been set.\nDo you want to use the' ' current date and time?') save_data.update(end_time=datetime.now()) if encounter.appointment: appointments.append(encounter.appointment) cls.write(encounters, save_data) Appointment = Pool().get('gnuhealth.appointment') Appointment.write(appointments, {'state': 'done'}) @classmethod @ModelView.button_action( 'health_encounter.health_wizard_encounter_edit_component') def add_component(cls, components, *a, **k): hp = HealthProfessional.get_health_professional() if not hp: cls.raise_user_error('health_professional_warning') @classmethod @ModelView.button_action( 'health_encounter.health_wizard_encounter_edit_component') def add_extra_component(cls, components, *a, **k): hp = HealthProfessional.get_health_professional() if not hp: cls.raise_user_error('health_professional_warning') @staticmethod def default_start_time(): return datetime.now() @staticmethod def default_institution(): return HealthInstitution().get_institution() @staticmethod def default_state(): return 'in_progress' @staticmethod def default_active(): return True def get_crypto_enabled(self, name): return False def get_rec_name(self, name): localstart = utils.localtime(self.start_time) line = [ 'EV%05d' % self.id, self.patient.name.name, '(%s /MRN:%s)' % (self.upi, self.medical_record_num), self.sex_display, self.age, 'on %s' % localstart.ctime() ] return ' '.join(line) def get_person_patient_field(self, name): if name in ['sex_display']: sex = getattr(self.patient.name, name, getattr(self.patient.name, 'sex', '?')) return len(sex) == 1 and sex.upper() or sex if name in ['age']: return getattr(self.patient, name) return '' def get_upi_mrn(self, name): if name == 'upi': return self.patient.puid elif name == 'medical_record_num': return getattr(self.patient, 'medical_record_num', '') return '' def get_encounter_summary(self, name): summary_texts = [] for component in self.components: real_component = component.union_unshard(component.id) report_info = real_component.report_info.split(u'\n') report_info.insert(1, real_component.byline) summary_texts.append(u'\n'.join(report_info)) # TODO: Show extra components differently from regular ones return u'\n\n'.join(summary_texts) def get_short_summary(self, name): summary_texts = [] for component in self.components: summary_texts.append( (component.component_type, component.critical_info)) return u'\n'.join([': '.join(x) for x in summary_texts]) def real_component(self, name=None): '''retuns the real component objects. Always returns a list of objects. If name not provided returns all real components name can be the name of the model or the shortname displayed on screen, case insensitive. ''' comps = [(x.component_type, x.union_unshard(x.id)) for x in self.components] typedict = {} real_comps = [] # modeldict = {} for i, (comptype, comp) in enumerate(comps): typedict.setdefault(comptype.lower(), []).append(i) # modeldict # ToDo: Figure out how to get at the model # name from an instance real_comps.append(comp) if name: return [real_comps[i] for i in typedict.get(name, [])] else: return real_comps def get_clinicians(self, name): '''returns a list of IDs for the clinicians that performed components linked here''' health_profs = [x.performed_by for x in self.components] health_profs.extend( [x.signed_by for x in self.components if x.sign_time]) return map(int, set(filter(None, health_profs))) @classmethod def search_clinicians(self, name, clause): fld, operator, operand = clause component_model = Pool().get('gnuhealth.encounter.component') components = component_model.search([ 'OR', ('performed_by', operator, operand), ('signed_by', operator, operand) ]) encounter_list = [ x.encounter.id for x in component_model.browse(components) ] return [('id', 'in', encounter_list)] @classmethod def get_patient_age(cls, instances, name): ''' Uses the AGE function in the database to calculate the age at the date at which the encounter started ''' c = Transaction().cursor tbl = cls.__table__() qry = "\n".join([ "SET intervalstyle TO 'iso_8601';", "SELECT a.id as id, COALESCE(btrim(lower(" "regexp_replace(AGE(a.start_time::date, c.dob)::varchar, " "'([YMD])', '\\1 ', 'g')), 'p '), '--') as showage ", "from " + str(tbl) + " as a ", " inner join gnuhealth_patient as b on a.patient=b.id", " inner join party_party c on b.name=c.id" " where a.id in %s ;" ]) qry_parm = tuple(map(int, instances)) c.execute(qry, (qry_parm, )) return dict([x for x in c.fetchall()])
@classmethod def generate_code(cls, institution, sector): return '-'.join([institution.code, sector.code]) @classmethod def create(cls, vlist): vlist = [x.copy() for x in vlist] for values in vlist: if not values.get('sync_code'): values['sync_code'] = cls.generate_code( values['name'], values['operational_sector']) return super(HealthInstitutionOperationalSector, cls).create(vlist) ENCTR_STATES = {'readonly': In(Eval('state'), ['signed', 'done', 'invalid'])} COMPT_STATES = {'readonly': Bool(Eval('signed_by'))} class PatientEncounter(ModelSQL, ModelView): 'Patient Encounter' __name__ = 'gnuhealth.encounter' fvty = fields.Boolean('First visit this year', states=ENCTR_STATES, help='Check if this is known to be the first time ' 'this patient is visiting this institution ' 'for this year') @fields.depends('patient', 'start_time', 'institution') def on_change_with_fvty(self, *arg, **kwarg): if self.institution and self.patient and self.start_time:
class AccountVoucher(ModelSQL, ModelView): 'Account Voucher' __name__ = 'account.voucher' _rec_name = 'number' number = fields.Char('Number', readonly=True, help="Voucher Number") party = fields.Many2One('party.party', 'Party', states={ 'required': ~Eval('active', True), 'readonly': In(Eval('state'), ['posted']), }) voucher_type = fields.Selection([ ('payment', 'Payment'), ('receipt', 'Receipt'), ], 'Type', select=True, required=True, states=_STATES) pay_lines = fields.One2Many('account.voucher.line.paymode', 'voucher', 'Pay Mode Lines', states=_STATES) date = fields.Date('Date', required=True, states=_STATES) journal = fields.Many2One('account.journal', 'Journal', required=True, states=_STATES) currency = fields.Many2One('currency.currency', 'Currency', states=_STATES) company = fields.Many2One('company.company', 'Company', states=_STATES) lines = fields.One2Many('account.voucher.line', 'voucher', 'Lines', states=_STATES) lines_credits = fields.One2Many('account.voucher.line.credits', 'voucher', 'Credits', states={ 'invisible': ~Eval('lines_credits'), }) lines_debits = fields.One2Many('account.voucher.line.debits', 'voucher', 'Debits', states={ 'invisible': ~Eval('lines_debits'), }) comment = fields.Text('Comment', states=_STATES) state = fields.Selection([ ('draft', 'Draft'), ('posted', 'Posted'), ('canceled', 'Canceled'), ], 'State', select=True, readonly=True) amount = fields.Function(fields.Numeric('Payment', digits=(16, 2)), 'on_change_with_amount') amount_to_pay = fields.Function(fields.Numeric('To Pay', digits=(16, 2)), 'on_change_with_amount_to_pay') amount_invoices = fields.Function( fields.Numeric('Invoices', digits=(16, 2)), 'on_change_with_amount_invoices') move = fields.Many2One('account.move', 'Move', readonly=True) move_canceled = fields.Many2One('account.move', 'Move Canceled', readonly=True, states={ 'invisible': ~Eval('move_canceled'), }) from_pay_invoice = fields.Boolean('Voucher launched from Pay invoice') amount_to_pay_words = fields.Char('Amount to Pay (Words)', states={'readonly': True}) transfer = fields.Boolean( 'Realizar movimiento', help= 'Realizar movimiento de caja a bancos, o transferencia entre bancos', states={ 'readonly': In(Eval('state'), ['posted']), }) @classmethod def __setup__(cls): super(AccountVoucher, cls).__setup__() cls._error_messages.update({ 'missing_pay_lines': 'You have to enter pay mode lines!', 'delete_voucher': 'You can not delete a voucher that is posted!', 'payment_advanced': u'¿Desea generar un anticipo?', }) cls._buttons.update({ 'post': { 'invisible': Eval('state') != 'draft', }, 'cancel': { 'invisible': Eval('state') != 'posted', }, }) cls._order.insert(0, ('date', 'DESC')) cls._order.insert(1, ('number', 'DESC')) @staticmethod def default_state(): return 'draft' @staticmethod def default_transfer(): return False @staticmethod def default_currency(): Company = Pool().get('company.company') company_id = Transaction().context.get('company') if company_id: return Company(company_id).currency.id @staticmethod def default_company(): return Transaction().context.get('company') @staticmethod def default_journal(): pool = Pool() Journal = pool.get('account.journal') journal = Journal.search([('type', '=', 'expense')]) journal_r = Journal.search([('type', '=', 'revenue')]) voucher_type_id = Transaction().context.get('voucher_type') if voucher_type_id == 'receipt': for j in journal_r: return j.id if voucher_type_id == 'payment': for j in journal: return j.id @staticmethod def default_date(): Date = Pool().get('ir.date') return Date.today() @staticmethod def default_from_pay_invoice(): return False def set_number(self): Sequence = Pool().get('ir.sequence') AccountVoucherSequence = Pool().get('account.voucher.sequence') sequence = AccountVoucherSequence(1) if self.voucher_type == 'payment': self.write([self], { 'number': Sequence.get_id(sequence.voucher_payment_sequence.id) }) else: self.write([self], { 'number': Sequence.get_id(sequence.voucher_receipt_sequence.id) }) @fields.depends('party', 'lines', 'pay_lines', 'lines_credits', 'lines_debits') def on_change_with_amount(self, name=None): amount = Decimal('0.0') if self.pay_lines: for line in self.pay_lines: if line.pay_amount: amount += line.pay_amount if self.lines_credits: for line in self.lines_credits: if line.amount_original: amount += line.amount_original if self.lines_debits: for line in self.lines_debits: if line.amount_original: amount += line.amount_original return amount @fields.depends('party', 'lines') def on_change_with_amount_to_pay(self, name=None): total = 0 if self.lines: for line in self.lines: total += line.amount_unreconciled or Decimal('0.00') return total @fields.depends('lines', 'pay_lines') def on_change_with_amount_invoices(self, name=None): total = 0 if self.lines: for line in self.lines: total += line.amount or Decimal('0.00') return total @fields.depends('party', 'voucher_type', 'lines', 'lines_credits', 'lines_debits', 'from_pay_invoice') def on_change_party(self): pool = Pool() Invoice = pool.get('account.invoice') MoveLine = pool.get('account.move.line') InvoiceAccountMoveLine = pool.get('account.invoice-account.move.line') Currency = pool.get('currency.currency') PaymentLine = pool.get('account.voucher.line') PaymentLineCredits = pool.get('account.voucher.line.credits') PaymentLineDebits = pool.get('account.voucher.line.debits') if self.from_pay_invoice: # The voucher was launched from Invoice's PayInvoice wizard: # 'lines', 'lines_credits', 'lines_debits' should be set there return {} lines = [] lines_credits = [] lines_debits = [] if self.lines: return if self.voucher_type == 'receipt': account_types = ['receivable'] else: account_types = ['payable'] move_lines = MoveLine.search([ ('party', '=', self.party), ('account.kind', 'in', account_types), ('state', '=', 'valid'), ('reconciliation', '=', None), ]) for line in move_lines: invoice = InvoiceAccountMoveLine.search([ ('line', '=', line.id), ]) if invoice: continue if line.credit: line_type = 'cr' amount = line.credit else: amount = line.debit line_type = 'dr' amount_residual = abs(line.amount_residual) name = '' model = str(line.origin) if model[:model.find(',')] == 'account.invoice': invoice = Invoice(line.origin.id) if invoice.type[0:3] == 'out': name = invoice.number else: name = invoice.reference payment_line = AccountVoucherLine() payment_line.name = name payment_line.account = line.account.id payment_line.amount = Decimal('0.00') payment_line.amount_original = amount payment_line.amount_unreconciled = amount_residual payment_line.line_type = line_type payment_line.move_line = line.id payment_line.date = line.date payment_line.date_expire = line.maturity_date if line.credit and self.voucher_type == 'receipt': lines_credits.append(payment_line) elif line.debit and self.voucher_type == 'payment': lines_debits.append(payment_line) else: lines.append(payment_line) self.lines = lines self.lines_credits = lines_credits self.lines_debits = lines_debits @classmethod def delete(cls, vouchers): if not vouchers: return True for voucher in vouchers: if voucher.state != 'draft': cls.raise_user_error('delete_voucher') return super(AccountVoucher, cls).delete(vouchers) def prepare_move_lines(self): pool = Pool() Period = pool.get('account.period') Move = pool.get('account.move') Invoice = pool.get('account.invoice') Sale = pool.get('sale.sale') original = Decimal(0.0) unreconcilied = Decimal(0.0) paid_amount = Decimal(0.0) residual_amount = Decimal(0.0) name = None invoice_d = None # Check amount if not self.amount > Decimal("0.0"): self.raise_user_error('missing_pay_lines') move_lines = [] line_move_ids = [] move, = Move.create([{ 'period': Period.find(self.company.id, date=self.date), 'journal': self.journal.id, 'date': self.date, 'origin': str(self), }]) self.write([self], { 'move': move.id, }) # # Pay Modes # if self.pay_lines: for line in self.pay_lines: if self.voucher_type == 'receipt': debit = line.pay_amount credit = Decimal('0.0') else: debit = Decimal('0.0') credit = line.pay_amount move_lines.append({ 'debit': debit, 'credit': credit, 'account': line.pay_mode.account.id, 'move': move.id, 'journal': self.journal.id, 'period': Period.find(self.company.id, date=self.date), }) # # Credits # if self.lines_credits: for line in self.lines_credits: debit = line.amount_original credit = Decimal('0.0') move_lines.append({ 'description': 'advance', 'debit': debit, 'credit': credit, 'account': line.account.id, 'move': move.id, 'journal': self.journal.id, 'period': Period.find(self.company.id, date=self.date), 'party': self.party.id, }) # # Debits # if self.lines_debits: for line in self.lines_debits: debit = Decimal('0.0') credit = line.amount_original move_lines.append({ 'description': 'advance', 'debit': debit, 'credit': credit, 'account': line.account.id, 'move': move.id, 'journal': self.journal.id, 'period': Period.find(self.company.id, date=self.date), 'party': self.party.id, }) # # Voucher Lines # total = self.amount if self.lines: for line in self.lines: if not line.amount: continue line_move_ids.append(line.move_line) if self.voucher_type == 'receipt': debit = Decimal('0.00') credit = line.amount else: debit = line.amount credit = Decimal('0.00') total -= line.amount move_lines.append({ 'description': Invoice(line.move_line.origin.id).number, 'debit': debit, 'credit': credit, 'account': line.account.id, 'move': move.id, 'journal': self.journal.id, 'period': Period.find(self.company.id, date=self.date), 'party': self.party.id, }) if total != Decimal('0.00'): if self.voucher_type == 'receipt': debit = Decimal('0.00') credit = total account_id = self.party.account_receivable.id else: debit = total credit = Decimal('0.00') account_id = self.party.account_payable.id move_lines.append({ 'description': self.number, 'debit': debit, 'credit': credit, 'account': account_id, 'move': move.id, 'journal': self.journal.id, 'period': Period.find(self.company.id, date=self.date), 'date': self.date, 'party': self.party.id, }) return move_lines def create_move(self, move_lines): pool = Pool() Move = pool.get('account.move') MoveLine = pool.get('account.move.line') Invoice = pool.get('account.invoice') created_lines = MoveLine.create(move_lines) Move.post([self.move]) Sale = pool.get('sale.sale') invoice_d = None sales = None name = None invoice = None for line in self.lines: original = line.amount_original unreconciled = line.amount_unreconciled name = line.name if name != None: invoice = Invoice.search([('number', '=', name), ('description', '!=', None)]) if invoice: for i in invoice: invoice_d = i.description if invoice_d != None: sales = Sale.search([('reference', '=', invoice_d)]) if sales: for s in sales: sale = s paid_amount = Decimal(original - unreconciled) residual_amount = Decimal(unreconciled) sale.get_residual_amount([sale], ['residual_amount']) sale.get_paid_amount([sale], ['paid_amount']) # reconcile check for line in self.lines: if line.amount == Decimal("0.00"): continue invoice = Invoice(line.move_line.origin.id) if self.voucher_type == 'receipt': amount = line.amount else: amount = -line.amount reconcile_lines, remainder = \ Invoice.get_reconcile_lines_for_amount( invoice, amount) for move_line in created_lines: if move_line.description == 'advance': continue if move_line.description == invoice.number: reconcile_lines.append(move_line) Invoice.write([invoice], { 'payment_lines': [('add', [move_line.id])], }) if remainder == Decimal('0.00'): MoveLine.reconcile(reconcile_lines) reconcile_lines = [] for line in self.lines_credits: reconcile_lines.append(line.move_line) for move_line in created_lines: if move_line.description == 'advance': reconcile_lines.append(move_line) MoveLine.reconcile(reconcile_lines) reconcile_lines = [] for line in self.lines_debits: reconcile_lines.append(line.move_line) for move_line in created_lines: if move_line.description == 'advance': reconcile_lines.append(move_line) MoveLine.reconcile(reconcile_lines) return True def create_cancel_move(self): pool = Pool() Move = pool.get('account.move') MoveLine = pool.get('account.move.line') Period = pool.get('account.period') Reconciliation = pool.get('account.move.reconciliation') Invoice = pool.get('account.invoice') Date = pool.get('ir.date') canceled_date = Date.today() canceled_move, = Move.copy( [self.move], { 'period': Period.find(self.company.id, date=canceled_date), 'date': canceled_date, }) self.write([self], { 'move_canceled': canceled_move.id, }) for line in canceled_move.lines: aux = line.debit line.debit = line.credit line.credit = aux line.save() Move.post([self.move_canceled]) reconciliations = [ x.reconciliation for x in self.move.lines if x.reconciliation ] with Transaction().set_user(0, set_context=True): if reconciliations: Reconciliation.delete(reconciliations) for line in self.lines: origin = str(line.move_line.origin) origin = origin[:origin.find(',')] if origin not in ['account.invoice', 'account.voucher']: continue if line.amount == Decimal("0.00"): continue invoice = Invoice(line.move_line.origin.id) for move_line in self.move_canceled.lines: if move_line.description == 'advance': continue if move_line.description == invoice.number: Invoice.write([invoice], { 'payment_lines': [('add', [move_line.id])], }) lines_to_reconcile = [] for line in self.move.lines: if line.account.reconcile: lines_to_reconcile.append(line) for cancel_line in canceled_move.lines: if cancel_line.account.reconcile: lines_to_reconcile.append(cancel_line) if lines_to_reconcile: MoveLine.reconcile(lines_to_reconcile) return True def prepare_postdated_lines(self): pool = Pool() Period = pool.get('account.period') Move = pool.get('account.move') Invoice = pool.get('account.invoice') postdated_lines = None if self.pay_lines: for line in self.pay_lines: if line.pay_mode.account.name == 'EFECTOS DE COBRO INMEDIATO (CHEQUES)': postdated_lines = [] postdated_lines.append({ 'reference': line.voucher.move, 'name': line.voucher.number, 'amount': line.pay_amount, 'account': line.pay_mode.account.id, 'date': line.fecha, }) return postdated_lines def create_postdated_check(self, postdated_lines): pool = Pool() Postdated = pool.get('account.postdated') PostdatedLine = pool.get('account.postdated.line') postdated = Postdated() if postdated_lines != None: for line in postdated_lines: date = line['date'] postdated.party = self.party postdated.post_check_type = 'receipt' postdated.journal = 1 postdated.lines = postdated_lines postdated.state = 'draft' postdated.date = date postdated.save() def get_value_lines(self): amount_invoice = self.amount if self.lines: res = {} for line in self.lines: if line.amount_unreconciled < amount_invoice: value = Decimal('0.0') amount_invoice -= line.amount_unreconciled line.write([line], {'amount': line.amount_unreconciled}) line.write([line], {'amount_unreconciled': value}) if line.amount_unreconciled >= amount_invoice: value = line.amount_unreconciled - amount_invoice line.write([line], {'amount': amount_invoice}) line.write([line], {'amount_unreconciled': value}) amount_invoice = Decimal('0.0') if amount_invoice != 0: warning_name = u'Tiene un excedente ¿Desea generar un anticipo?' self.raise_user_warning(warning_name, 'payment_advanced') def get_amount2words(self, value): if conversor: return (conversor.cardinal(int(value))).upper() else: return '' def get_toWords(self): if self.lines: amount = Decimal('0.0') for line in self.lines: amount += line.amount value_words = self.get_amount2words(amount) self.write([self], {'amount_to_pay_words': value_words}) @classmethod @ModelView.button def post(cls, vouchers): pool = Pool() module = None Module = pool.get('ir.module') module = Module.search([('name', '=', 'nodux_account_postdated_check'), ('state', '=', 'installed')]) for voucher in vouchers: voucher.get_value_lines() voucher.get_toWords() voucher.set_number() move_lines = voucher.prepare_move_lines() voucher.create_move(move_lines) if module: postdated_lines = voucher.prepare_postdated_lines() voucher.create_postdated_check(postdated_lines) cls.write(vouchers, {'state': 'posted'}) @classmethod @ModelView.button def cancel(cls, vouchers): for voucher in vouchers: voucher.create_cancel_move() cls.write(vouchers, {'state': 'canceled'}) @classmethod def view_attributes(cls): return super(AccountVoucher, cls).view_attributes() + [ ('//page[@id="pay_lines"]', 'states', { 'invisible': Eval('transfer'), }), ('//page[@id="lines"]', 'states', { 'invisible': Eval('transfer'), }), ('//page[@id="info"]', 'states', { 'invisible': Eval('transfer'), }) ]
class PurchaseRequest(ModelSQL, ModelView): 'Purchase Request' __name__ = 'purchase.request' product = fields.Many2One('product.product', 'Product', select=True, readonly=True, domain=[('purchasable', '=', True)]) description = fields.Text('Description', readonly=True, states=STATES, depends=DEPENDS) party = fields.Many2One('party.party', 'Party', select=True, states=STATES, depends=DEPENDS) quantity = fields.Float('Quantity', required=True, states=STATES, digits=(16, Eval('uom_digits', 2)), depends=DEPENDS + ['uom_digits']) uom = fields.Many2One('product.uom', 'UOM', select=True, ondelete='RESTRICT', domain=[ ('category', '=', Eval('product_uom_category')), ], states={ 'required': Bool(Eval('product')), 'readonly': STATES['readonly'], }, depends=['product', 'product_uom_category'] + DEPENDS) uom_digits = fields.Function(fields.Integer('UOM Digits'), 'on_change_with_uom_digits') product_uom_category = fields.Function( fields.Many2One('product.uom.category', "Product Uom Category"), 'on_change_with_product_uom_category') computed_quantity = fields.Float('Computed Quantity', readonly=True) computed_uom = fields.Many2One('product.uom', 'Computed UOM', readonly=True) purchase_date = fields.Date('Best Purchase Date', readonly=True) supply_date = fields.Date('Expected Supply Date', readonly=True) default_uom_digits = fields.Function(fields.Integer('Default UOM Digits'), 'on_change_with_default_uom_digits') stock_level = fields.Float('Stock at Supply Date', readonly=True, digits=(16, Eval('default_uom_digits', 2)), depends=['default_uom_digits']) warehouse = fields.Many2One('stock.location', "Warehouse", states={ 'required': Eval('warehouse_required', False), }, domain=[('type', '=', 'warehouse')], depends=['warehouse_required'], readonly=True) warehouse_required = fields.Function(fields.Boolean('Warehouse Required'), 'get_warehouse_required') purchase_line = fields.Many2One('purchase.line', 'Purchase Line', readonly=True) purchase = fields.Function(fields.Many2One('purchase.purchase', 'Purchase'), 'get_purchase', searcher='search_purchase') company = fields.Many2One('company.company', 'Company', required=True, readonly=True, domain=[ ('id', If(In('company', Eval('context', {})), '=', '!='), Eval('context', {}).get('company', -1)), ]) origin = fields.Reference('Origin', selection='get_origin', readonly=True) exception_ignored = fields.Boolean('Ignored Exception') state = fields.Selection([ ('purchased', "Purchased"), ('done', "Done"), ('draft', "Draft"), ('cancel', "Cancel"), ('exception', "Exception"), ], "State", required=True, readonly=True, select=True) @classmethod def __setup__(cls): super(PurchaseRequest, cls).__setup__() cls._order[0] = ('id', 'DESC') cls._buttons.update({ 'handle_purchase_cancellation_exception': { 'invisible': Eval('state') != 'exception', 'depends': ['state'], }, }) @classmethod def __register__(cls, module_name): pool = Pool() ModelData = pool.get('ir.model.data') Purchase = pool.get('purchase.purchase') PurchaseLine = pool.get('purchase.line') model_data = ModelData.__table__() purchase = Purchase.__table__() purchase_line = PurchaseLine.__table__() request = cls.__table__() tablehandler = cls.__table_handler__(module_name) state_exist = tablehandler.column_exist('state') super(PurchaseRequest, cls).__register__(module_name) # Migration from 3.6: removing the constraint on the quantity tablehandler = cls.__table_handler__(module_name) tablehandler.drop_constraint('check_purchase_request_quantity') # Migration from 3.8: renaming module of Purchase Request group entry cursor = Transaction().connection.cursor() cursor.execute(*model_data.update( columns=[model_data.module], values=['purchase_request'], where=((model_data.fs_id == 'group_purchase_request') & (model_data.module == 'stock_supply')))) # Migration from 4.0: remove required on product and uom tablehandler.not_null_action('product', action='remove') tablehandler.not_null_action('uom', action='remove') # Migration from 4.2: add state if not state_exist: cursor = Transaction().connection.cursor() update = Transaction().connection.cursor() query = request.join( purchase_line, type_='INNER', condition=request.purchase_line == purchase_line.id).join( purchase, type_='INNER', condition=purchase_line.purchase == purchase.id).select( request.id, purchase.state, request.exception_ignored) cursor.execute(*query) for request_id, purchase_state, exception_ignored in cursor: if purchase_state == 'cancel' and not exception_ignored: state = 'exception' elif purchase_state == 'cancel': state = 'cancel' elif purchase_state == 'done': state = 'done' else: state = 'purchased' update.execute(*request.update([request.state], [state], where=request.id == request_id)) # Migration from 4.4: remove required on origin tablehandler.not_null_action('origin', action='remove') def get_rec_name(self, name): pool = Pool() Lang = pool.get('ir.lang') if self.product: lang = Lang.get() rec_name = (lang.format('%.*f', (self.uom.digits, self.quantity)) + '%s %s' % (self.uom.symbol, self.product.name)) elif self.description: rec_name = self.description.splitlines()[0] else: rec_name = str(self.id) if self.warehouse: return "%s @% s" % (rec_name, self.warehouse.name) else: return rec_name @classmethod def search_rec_name(cls, name, clause): res = [] names = clause[2].split('@', 1) res.append(('product.template.name', clause[1], names[0])) if len(names) != 1 and names[1]: res.append(('warehouse', clause[1], names[1])) return [ 'OR', res, ('description', ) + tuple(clause[1:]), ] @staticmethod def default_company(): return Transaction().context.get('company') @staticmethod def default_exception_ignored(): return False def get_purchase(self, name): if self.purchase_line: return self.purchase_line.purchase.id @classmethod def search_purchase(cls, name, clause): return [('purchase_line.' + clause[0], ) + tuple(clause[1:])] @property def currency(self): return self.company.currency @classmethod def default_state(cls): return 'draft' def get_state(self): if self.purchase_line: if (self.purchase_line.purchase.state == 'cancel' and not self.exception_ignored): return 'exception' elif self.purchase_line.purchase.state == 'cancel': return 'cancel' elif self.purchase_line.purchase.state == 'done': return 'done' else: return 'purchased' return 'draft' @classmethod def update_state(cls, requests): for request in requests: state = request.get_state() if state != request.state: request.state = state cls.save(requests) def get_warehouse_required(self, name): return self.product and self.product.type in ('goods', 'assets') @fields.depends('uom') def on_change_with_uom_digits(self, name=None): if self.uom: return self.uom.digits return 2 @fields.depends('product') def on_change_with_product_uom_category(self, name=None): if self.product: return self.product.default_uom_category.id @fields.depends('product') def on_change_with_default_uom_digits(self, name=None): if self.product: return self.product.default_uom.digits return 2 @classmethod def _get_origin(cls): 'Return the set of Model names for origin Reference' return set() @classmethod def get_origin(cls): pool = Pool() IrModel = pool.get('ir.model') models = IrModel.search([ ('model', 'in', list(cls._get_origin())), ]) return [(None, '')] + [(m.model, m.name) for m in models] @classmethod def view_attributes(cls): return [ ('/tree', 'visual', If(Eval('state') == 'cancel', 'muted', '')), ] @classmethod def create(cls, vlist): for vals in vlist: for field_name in ('quantity', 'company'): if vals.get(field_name) is None: raise AccessError( gettext('purchase_request.msg_request_no_create')) return super(PurchaseRequest, cls).create(vlist) @classmethod def delete(cls, requests): for request in requests: if request.purchase_line: raise AccessError( gettext('purchase_request.msg_request_delete_purchased', request=request.rec_name)) super(PurchaseRequest, cls).delete(requests) @classmethod def find_best_product_supplier(cls, product, date, **pattern): "Return the best product supplier to request product at date" pool = Pool() Date = pool.get('ir.date') today = Date.today() for product_supplier in product.product_suppliers_used(**pattern): supply_date = product_supplier.compute_supply_date(date=today) timedelta = date - supply_date if timedelta >= datetime.timedelta(0): return product_supplier @classmethod def find_best_supplier(cls, product, date, **pattern): ''' Return the best supplier and purchase_date for the product. ''' pool = Pool() Date = pool.get('ir.date') product_supplier = cls.find_best_product_supplier( product, date, **pattern) if product_supplier: supplier = product_supplier.party purchase_date = product_supplier.compute_purchase_date(date) else: supplier = None purchase_date = Date.today() return supplier, purchase_date @classmethod @ModelView.button_action( 'purchase_request.wizard_purchase_cancellation_handle_exception') def handle_purchase_cancellation_exception(cls, purchases): pass