Example #1
0
class SubscriptionLine(metaclass=PoolMeta):
    __name__ = 'sale.subscription.line'

    asset_lot = fields.Many2One(
        'stock.lot',
        "Asset Lot",
        domain=[
            ('subscription_services', '=', Eval('service')),
        ],
        states={
            'required': ((Eval('subscription_state') == 'running')
                         & Eval('asset_lot_required')),
            'invisible':
            ~Eval('asset_lot_required'),
            'readonly':
            Eval('subscription_state') != 'draft',
        },
        depends=['service', 'subscription_state', 'asset_lot_required'])
    asset_lot_required = fields.Function(fields.Boolean("Asset Lot Required"),
                                         'on_change_with_asset_lot_required')

    @classmethod
    def __setup__(cls):
        super(SubscriptionLine, cls).__setup__()

        cls.quantity.domain = [
            cls.quantity.domain,
            If(Bool(Eval('asset_lot')), ('quantity', '=', 1), ()),
        ]
        cls.quantity.depends.append('asset_lot')

    @fields.depends('service')
    def on_change_with_asset_lot_required(self, name=None):
        if not self.service:
            return False
        return bool(self.service.asset_lots)

    @classmethod
    def copy(cls, lines, default=None):
        if default is None:
            default = {}
        else:
            default = default.copy()
        default.setdefault('lot')
        return super(SubscriptionLine, cls).copy(lines, default)

    @classmethod
    def validate(cls, lines):
        super(SubscriptionLine, cls).validate(lines)
        cls._validate_dates(lines)

    @classmethod
    def _validate_dates(cls, lines):
        transaction = Transaction()
        connection = transaction.connection
        cursor = connection.cursor()

        transaction.database.lock(connection, cls._table)

        line = cls.__table__()
        other = cls.__table__()
        overlap_where = (((line.end_date == Null)
                          & ((other.end_date == Null)
                             | (other.start_date > line.start_date)
                             | (other.end_date > line.start_date)))
                         | ((line.end_date != Null)
                            & (((other.end_date == Null)
                                & (other.start_date < line.end_date))
                               | ((other.end_date != Null)
                                  & (((other.end_date >= line.start_date)
                                      & (other.end_date < line.end_date))
                                     |
                                     ((other.start_date >= line.start_date)
                                      &
                                      (other.start_date < line.end_date)))))))
        for sub_lines in grouped_slice(lines):
            sub_ids = [l.id for l in sub_lines]
            cursor.execute(
                *line.join(other,
                           condition=((line.id != other.id)
                                      & (line.asset_lot == other.asset_lot))
                           ).select(line.id,
                                    other.id,
                                    where=((line.asset_lot != Null)
                                           & reduce_ids(line.id, sub_ids)
                                           & overlap_where),
                                    limit=1))
            overlapping = cursor.fetchone()
            if overlapping:
                sline1, sline2 = cls.browse(overlapping)
                raise ValidationError(
                    gettext('sale_subscription_asset.msg_asset_line_overlap',
                            line1=sline1.rec_name,
                            line2=sline2.rec_name))
Example #2
0
class Template:
    "Product Template"
    __metaclass__ = PoolMeta
    __name__ = 'product.template'

    manufacturers_code = fields.Char('Manufacturers_code')
    medical_insurance_code = fields.Char('Medical_insurance_code', select=True)
    attach = fields.Char('Attach', select=True)
    concentration = fields.Char('Concentration', select=True)  #
    concentration_unit = fields.Char('Concentration_unit', select=True)
    dose = fields.Char('Dose', select=True)  #
    dose_unit = fields.Char('Dose_unit', select=True)
    retrieve_the_code = fields.Char('Retrieve_the_code',
                                    select=True,
                                    required=True)
    capacity = fields.Char('Capacity', select=True, required=False)  #
    drug_specifications = fields.Function(
        fields.Char('Drug_specifications', select=True, readonly=True),
        'get_drug_specifications')
    is_direct_sending = fields.Boolean('Is_direct_sending', select=True)
    is_antimicrobials = fields.Boolean('Is_antimicrobials', select=True)
    a_charge = fields.Integer('A_charge', select=True)
    drup_level = fields.Char('Drup_level', select=True)
    compound_dose = fields.Float('Compound_dose', select=True)
    purchase_code = fields.Char('purchase_code', select=True, required=True)
    retail_package = fields.Many2One('product.uom', 'Retail Package')
    medical_insurance_description = fields.Char(
        'Medical_insurance_description', select=True)
    new_term = fields.Char('new_term', select=True)
    state = fields.Char('State', select=True, required=False)
    min_Package = fields.Many2One('product.uom', 'Min_Package', required=True)
    dosage_form_description = fields.Char('Dosage_form_description',
                                          select=True)
    manufacturers_describtion = fields.Char('Manufacturers_describtion',
                                            select=True,
                                            required=False)
    poison_hemp_spirit = fields.Selection([('common', u'普通'),
                                           ('narcosis', u'麻醉'),
                                           ('spirit_one', u'精神1'),
                                           ('spirit_two', u'精神2')],
                                          'Poison_hemp_spirit',
                                          select=True)
    national_essential_medicines = fields.Boolean(
        'National_essential_medicines', select=True)
    interim = fields.Selection([('1', u''), ('2', u'是')],
                               'interim',
                               select=True)
    approval_number = fields.Char('Approval number')
    is_atict = fields.Boolean('is_atict')
    homemade = fields.Boolean('homemade')

    def get_drug_specifications(self, name):
        if self.dose != None and self.dose_unit != '':
            drug_specificationss = str(self.dose.encode('utf-8')) + str(
                (self.dose_unit).encode('utf-8')) + '*' + str(
                    (self.capacity).encode('utf-8')) + str(
                        self.min_Package.name.encode('utf-8'))
        elif self.concentration != None and self.concentration_unit != None:
            drug_specificationss = str(self.concentration).encode('utf-8') + (
                self.concentration_unit).encode('utf-8') + '*' + str(
                    (self.capacity).encode('utf-8')) + str(
                        self.min_Package.name.encode('utf-8'))
        else:
            drug_specificationss = '*' + str(
                (self.capacity).encode('utf-8')) + str(
                    self.min_Package.name.encode('utf-8'))
        return drug_specificationss
Example #3
0
class ActionActWindowDomain(sequence_ordered(), DeactivableMixin, ModelSQL,
                            ModelView):
    "Action act window domain"
    __name__ = 'ir.action.act_window.domain'
    name = fields.Char('Name', translate=True)
    domain = fields.Char('Domain')
    count = fields.Boolean('Count')
    act_window = fields.Many2One('ir.action.act_window',
                                 'Action',
                                 select=True,
                                 required=True,
                                 ondelete='CASCADE')

    @classmethod
    def __register__(cls, module_name):
        super().__register__(module_name)

        table = cls.__table_handler__(module_name)

        # Migration from 5.0: remove required on sequence
        table.not_null_action('sequence', 'remove')

    @classmethod
    def default_count(cls):
        return False

    @classmethod
    def validate(cls, actions):
        super(ActionActWindowDomain, cls).validate(actions)
        cls.check_domain(actions)

    @classmethod
    def check_domain(cls, actions):
        for action in actions:
            if not action.domain:
                continue
            try:
                value = PYSONDecoder().decode(action.domain)
            except Exception:
                value = None
            if isinstance(value, PYSON):
                if not value.types() == set([list]):
                    value = None
            elif not isinstance(value, list):
                value = None
            else:
                try:
                    fields.domain_validate(value)
                except Exception:
                    value = None
            if value is None:
                raise DomainError(
                    gettext('ir.msg_action_invalid_domain',
                            domain=action.domain,
                            action=action.rec_name))

    @classmethod
    def create(cls, vlist):
        pool = Pool()
        domains = super(ActionActWindowDomain, cls).create(vlist)
        pool.get('ir.action.keyword')._get_keyword_cache.clear()
        return domains

    @classmethod
    def write(cls, domains, values, *args):
        pool = Pool()
        super(ActionActWindowDomain, cls).write(domains, values, *args)
        pool.get('ir.action.keyword')._get_keyword_cache.clear()

    @classmethod
    def delete(cls, domains):
        pool = Pool()
        super(ActionActWindowDomain, cls).delete(domains)
        pool.get('ir.action.keyword')._get_keyword_cache.clear()
class EncounterComponentType(ModelSQL, ModelView):
    '''Encounter Component
    Stores encounter component type definitions. The Encounter models
    and views use this model to determine which components are available
    '''
    __name__ = 'gnuhealth.encounter.component_type'
    name = fields.Char('Type Name')
    code = fields.Char('Code',
                       size=15,
                       help="Short name Displayed in the first column of the"
                       "encounter. Maximum 15 characters")
    model = fields.Char('Model name',
                        help='e.g. gnuhealth.encounter.clinical',
                        required=True)
    view_form = fields.Char('View name',
                            required=True,
                            help='full xml id of view, e.g. module.xml_id')
    ordering = fields.Integer('Display order')
    active = fields.Boolean('Active')

    @classmethod
    def __setup__(cls):
        super(EncounterComponentType, cls).__setup__()
        cls._order = [('ordering', 'ASC'), ('name', 'ASC')]

    @classmethod
    def register_type(cls, model_class, view):
        # first check if it was previously registered and deactivated
        registration = cls.search([('model', '=', model_class.__name__),
                                   ('view_form', '=', view)])
        if registration:
            registration = cls.browse(registration)
            if not registration.active:
                cls.write(registration, {'active': True})
        else:
            cdata = {'model': model_class.__name__, 'view_form': view}
            cdata['name'] = ''.join(
                filter(None, model_class.__doc__.split('\n'))[:1])
            cdata['code'] = cdata['name'][:15]

            # we need to create the registration
            cls.create([cdata])
        return True

    @classmethod
    def get_selection_list(cls):
        '''returns a list of active Encounter component types in a tuple
        of (id, Name, Code, model)'''
        try:
            return cls._component_type_list
        except AttributeError:
            pass
        cursor = Transaction().cursor
        TableHandler = backend.get('TableHandler')
        if not TableHandler.table_exist(cursor,
                                        'gnuhealth_encounter_component_type'):
            return []
        ectypes = cls.search_read([('active', '=', True)],
                                  fields_names=['id', 'name', 'code', 'model'],
                                  order=[('ordering', 'ASC'), ('name', 'ASC')])
        cls._component_type_list = [
            ComponentTypeInfo(x['id'], x['name'], x['code'], x['model'])
            for x in ectypes
        ]
        return cls._component_type_list

    @classmethod
    def get_view_name(cls, ids):
        '''returns the name of the view used to edit/display a
        component type'''
        if not isinstance(ids, (list, tuple)):
            ids = [ids]
        # ids = map(int, ids)
        forms = cls.read(ids, fields_names=['view_form'])
        if forms:
            return forms[0]['view_form']
        return None
Example #5
0
class Line:
    __metaclass__ = PoolMeta
    __name__ = 'account.move.line'

    reverse_moves = fields.Function(fields.Boolean('With Reverse Moves'),
        'get_reverse_moves', searcher='search_reverse_moves')
    netting_moves = fields.Function(fields.Boolean('With Netting Moves'),
        'get_netting_moves', searcher='search_netting_moves')

    def get_reverse_moves(self, name):
        if (not self.account
                or self.account.kind not in ['receivable', 'payable']):
            return False
        domain = [
            ('account', '=', self.account.id),
            ('reconciliation', '=', None),
            ]
        if self.party:
            domain.append(('party', '=', self.party.id))
        if self.credit > Decimal('0.0'):
            domain.append(('debit', '>', 0))
        if self.debit > Decimal('0.0'):
            domain.append(('credit', '>', 0))
        moves = self.search(domain, limit=1)
        return len(moves) > 0

    @classmethod
    def search_reverse_moves(cls, name, clause):
        operator = 'in' if clause[2] else 'not in'
        query = """
            SELECT
                id
            FROM
                account_move_line l
            WHERE
                (account, party) IN (
                    SELECT
                        aa.id,
                        aml.party
                    FROM
                        account_account aa,
                        account_move_line aml
                    WHERE
                        aa.reconcile
                        AND aa.id = aml.account
                        AND aml.reconciliation IS NULL
                    GROUP BY
                        aa.id,
                        aml.party
                    HAVING
                        bool_or(aml.debit <> 0)
                        AND bool_or(aml.credit <> 0)
                    )
            """
        cursor = Transaction().connection.cursor()
        cursor.execute(query)
        return [('id', operator, [x[0] for x in cursor.fetchall()])]

    def get_netting_moves(self, name):
        if (not self.account or not self.account.kind in
                ['receivable', 'payable']):
            return False
        if not self.account.party_required:
            return False
        domain = [
            ('party', '=', self.party.id),
            ('reconciliation', '=', None),
            ]
        if self.credit > Decimal('0.0'):
            domain.append(('debit', '>', 0))
        if self.debit > Decimal('0.0'):
            domain.append(('credit', '>', 0))
        moves = self.search(domain, limit=1)
        return len(moves) > 0

    @classmethod
    def search_netting_moves(cls, name, clause):
        operator = 'in' if clause[2] else 'not in'
        query = """
            SELECT
                id
            FROM
                account_move_line l
            WHERE
                party IN (
                    SELECT
                        aml.party
                    FROM
                        account_account aa,
                        account_move_line aml
                    WHERE
                        aa.reconcile
                        AND aa.id = aml.account
                        AND aml.reconciliation IS NULL
                    GROUP BY
                        aml.party
                    HAVING
                        bool_or(aml.debit <> 0)
                        AND bool_or(aml.credit <> 0)
                    )
            """
        cursor = Transaction().connection.cursor()
        cursor.execute(query)
        return [('id', operator, [x[0] for x in cursor.fetchall()])]
Example #6
0
class Component(ModelSQL, ModelView):
    'Component'
    __name__ = 'lims.component'

    equipment = fields.Many2One('lims.equipment',
                                'Equipment',
                                required=True,
                                ondelete='CASCADE',
                                select=True)
    kind = fields.Many2One('lims.component.kind', 'Kind', required=True)
    location = fields.Many2One('lims.component.location', 'Location')
    product_type = fields.Function(
        fields.Many2One('lims.product.type', 'Product type'),
        'get_product_type')
    comercial_product = fields.Many2One('lims.comercial.product',
                                        'Comercial product')
    capacity = fields.Char('Capacity (lts)')
    serial_number = fields.Char('Serial number')
    model = fields.Char('Model')
    power = fields.Char('Power')
    brand = fields.Many2One('lims.brand', 'Brand')
    internal_id = fields.Char('Internal ID Code')
    customer_description = fields.Char('Customer description')
    year_manufacturing = fields.Integer('Year of manufacturing')
    plant = fields.Function(fields.Many2One('lims.plant', 'Plant'),
                            'get_plant',
                            searcher='search_plant')
    party = fields.Function(fields.Many2One('party.party', 'Party'),
                            'get_party',
                            searcher='search_party')
    missing_data = fields.Boolean('Missing data')

    @classmethod
    def __setup__(cls):
        super().__setup__()
        cls._order.insert(0, ('equipment', 'ASC'))
        cls._order.insert(1, ('kind', 'ASC'))
        t = cls.__table__()
        cls._sql_constraints = [
            ('kind_location_description_unique',
             Unique(t, t.equipment, t.kind, t.location,
                    t.customer_description),
             'lims_industry.msg_component_unique'),
        ]

    @classmethod
    def __register__(cls, module_name):
        table_h = cls.__table_handler__(module_name)
        type_exist = table_h.column_exist('type')
        super().__register__(module_name)
        if type_exist:
            cursor = Transaction().connection.cursor()
            ComponentType = Pool().get('lims.component.type')
            cursor.execute('UPDATE "' + cls._table + '" c '
                           'SET kind = ct.kind, location = ct.location '
                           'FROM "' + ComponentType._table + '" ct '
                           'WHERE ct.id = c.type')
            table_h.drop_constraint('type_unique')
            table_h.drop_constraint('type_description_unique')
            table_h.drop_column('type')

    @classmethod
    def create(cls, vlist):
        TaskTemplate = Pool().get('lims.administrative.task.template')
        components = super().create(vlist)
        TaskTemplate.create_tasks('component_missing_data',
                                  cls._for_task_missing_data(components))
        return components

    @classmethod
    def _for_task_missing_data(cls, components):
        AdministrativeTask = Pool().get('lims.administrative.task')
        res = []
        for component in components:
            if not component.missing_data:
                continue
            if AdministrativeTask.search([
                ('type', '=', 'component_missing_data'),
                ('origin', '=', '%s,%s' % (cls.__name__, component.id)),
                ('state', 'not in', ('done', 'discarded')),
            ]):
                continue
            res.append(component)
        return res

    @classmethod
    def delete(cls, components):
        cls.check_delete(components)
        super().delete(components)

    @classmethod
    def check_delete(cls, components):
        Sample = Pool().get('lims.sample')
        for component in components:
            samples = Sample.search_count([
                ('component', '=', component.id),
            ])
            if samples != 0:
                raise UserError(
                    gettext('lims_industry.msg_delete_component',
                            component=component.get_rec_name(None)))

    @classmethod
    def copy(cls, records, default=None):
        if default is None:
            default = {}
        current_default = default.copy()

        new_records = []
        for record in records:
            current_default['customer_description'] = '%s (copy)' % (
                record.customer_description)
            new_record, = super().copy([record], default=current_default)
            new_records.append(new_record)
        return new_records

    def get_rec_name(self, name):
        res = self.kind.rec_name
        if self.location:
            res += ' ' + self.location.name
        if self.brand:
            res += ' - ' + self.brand.rec_name
        if self.model:
            res += ' - ' + self.model
        if self.customer_description:
            res += ' [' + self.customer_description + ']'
        return res

    @classmethod
    def search_rec_name(cls, name, clause):
        return [
            'OR',
            ('kind.name', ) + tuple(clause[1:]),
            ('location.name', ) + tuple(clause[1:]),
            ('brand.name', ) + tuple(clause[1:]),
            ('model', ) + tuple(clause[1:]),
            ('customer_description', ) + tuple(clause[1:]),
        ]

    @classmethod
    def get_plant(cls, component, name):
        result = {}
        for c in component:
            result[c.id] = c.equipment and c.equipment.plant.id or None
        return result

    @classmethod
    def search_plant(cls, name, clause):
        return [('equipment.plant', ) + tuple(clause[1:])]

    @classmethod
    def get_party(cls, component, name):
        result = {}
        for c in component:
            result[c.id] = c.equipment and c.equipment.plant.party.id or None
        return result

    @classmethod
    def search_party(cls, name, clause):
        return [('equipment.plant.party', ) + tuple(clause[1:])]

    @fields.depends('kind', '_parent_kind.product_type')
    def on_change_with_product_type(self, name=None):
        return self.get_product_type([self], name)[self.id]

    @classmethod
    def get_product_type(cls, components, name):
        result = {}
        for c in components:
            result[c.id] = c.kind and c.kind.product_type.id or None
        return result
Example #7
0
class SupportRequest (ModelSQL, ModelView):
    'Support Request Registration'
    __name__ = 'gnuhealth.support_request'
    _rec_name = 'code'

    code = fields.Char('Code',help='Request Code', readonly=True)

    operator = fields.Many2One(
        'gnuhealth.healthprofessional', 'Operator',
        help="Operator who took the call / support request")

    requestor = fields.Many2One('party.party', 'Requestor',
    domain=[('is_person', '=', True)], help="Related party (person)")

    patient = fields.Many2One('gnuhealth.patient', 'Patient')

    evaluation = fields.Many2One('gnuhealth.patient.evaluation',
        'Evaluation', 
        domain=[('patient', '=', Eval('patient'))], depends=['patient'],
        help='Related Patient Evaluation')

    request_date = fields.DateTime('Date', required=True,
        help="Date and time of the call for help")
    
    operational_sector = fields.Many2One('gnuhealth.operational_sector',
        'O. Sector',help="Operational Sector")

    latitude = fields.Numeric('Latidude', digits=(3, 14))
    longitude = fields.Numeric('Longitude', digits=(4, 14))

    address = fields.Text("Address", help="Free text address / location")
    urladdr = fields.Char(
        'OSM Map',
        help="Maps the location on Open Street Map")

    healthcenter = fields.Many2One('gnuhealth.institution','Calling Institution')

    patient_sex = fields.Function(
        fields.Char('Sex'),
        'get_patient_sex')

    patient_age = fields.Function(
        fields.Char('Age'),
        'get_patient_age')

    complaint = fields.Function(
        fields.Char('Chief Complaint'),
        'get_patient_complaint')

    urgency = fields.Selection([
        (None, ''),
        ('low', 'Low'),
        ('urgent', 'Urgent'),
        ('emergency', 'Emergency'),
        ], 'Urgency', sort=False)
       
    place_occurrance = fields.Selection([
        (None, ''),
        ('home', 'Home'),
        ('street', 'Street'),
        ('institution', 'Institution'),
        ('school', 'School'),
        ('commerce', 'Commercial Area'),
        ('recreational', 'Recreational Area'),
        ('transportation', 'Public transportation'),
        ('sports', 'Sports event'),
        ('publicbuilding', 'Public Building'),
        ('unknown', 'Unknown'),
        ], 'Origin', help="Place of occurrance",sort=False)

    event_type = fields.Selection([
        (None, ''),
        ('event1', 'Acute Coronary Syndrome'),
        ('event2', 'Acute pain'),
        ('event3', 'Acute illness'),
        ('event4', 'Allergic reaction'),
        ('event5', 'Bullying, battering'),
        ('event6', 'Gastrointestinal event'),
        ('event7', 'Endocrine event (diabetes, adrenal crisis, ..)'),
        ('event8', 'Choke'),
        ('event9', 'Domestic violence'),
        ('event10', 'Environmental event (weather, animals, ...)'),
        ('event11', 'Sexual assault'),
        ('event12', 'Drug intoxication'),
        ('event13', 'Robbery, violent assault'),
        ('event14', 'Respiratory distress'),
        ('event15', 'Pregnancy related event'),
        ('event16', 'Gas intoxication'),
        ('event17', 'Food intoxication'),
        ('event18', 'Neurological event (stroke, TIA, seizure, ...)'),
        ('event19', 'Chronic illness'),
        ('event20', 'Near drowning'),
        ('event21', 'Eye, Ear and Nose event'),
        ('event22', 'Fall'),
        ('event23', 'Deceased person'),
        ('event24', 'Psychiatric event'),
        ('event25', 'Suicide attempt'),
        ('event26', 'Fire'),
        ('event27', 'Transportation accident'),
        ('event28', 'Traumatic Injuries'),
        ('event29', 'Explosion'),
        ('event30', 'Other specified'),
        ], 'Event type')

    event_specific = fields.Many2One ('gnuhealth.pathology','Incident')

    multiple_casualties = fields.Boolean('Multiple Casualties')

    request_actions = fields.One2Many(
        'gnuhealth.support_request.log', 'sr',
        'Activities', help='Support request activity log')

    ambulances = fields.One2Many(
        'gnuhealth.ambulance.support', 'sr',
        'Ambulances', help='Ambulances requested in this Support Request')

    request_extra_info = fields.Text('Details')

    state = fields.Selection([
        (None, ''),
        ('open', 'Open'),
        ('closed', 'Closed'),
        ], 'State', sort=False, readonly=True)
 
    @staticmethod
    def default_request_date():
        return datetime.now()

    
    def get_patient_sex(self, name):
        if self.patient:
            return self.patient.gender

    def get_patient_age(self, name):
        if self.patient:
            return self.patient.name.age

    def get_patient_complaint(self, name):
        if self.evaluation:
            if self.evaluation.chief_complaint:
                return self.evaluation.chief_complaint

    @staticmethod
    def default_operator():
        pool = Pool()
        HealthProf= pool.get('gnuhealth.healthprofessional')
        operator = HealthProf.get_health_professional()
        return operator

    @staticmethod
    def default_state():
        return 'open'


    @fields.depends('latitude', 'longitude')
    def on_change_with_urladdr(self):
        # Generates the URL to be used in OpenStreetMap
        # The address will be mapped to the URL in the following way
        # If the latitud and longitude of the Accident / Injury 
        # are given, then those parameters will be used.

        ret_url = ''
        if (self.latitude and self.longitude):
            ret_url = 'http://openstreetmap.org/?mlat=' + \
                str(self.latitude) + '&mlon=' + str(self.longitude)

        return ret_url

    @classmethod
    def create(cls, vlist):
        Sequence = Pool().get('ir.sequence')
        Config = Pool().get('gnuhealth.sequences')

        vlist = [x.copy() for x in vlist]
        for values in vlist:
            if not values.get('code'):
                config = Config(1)
                values['code'] = Sequence.get_id(
                    config.support_request_code_sequence.id)

        return super(SupportRequest, cls).create(vlist)


    @classmethod
    def __setup__(cls):
        super(SupportRequest, cls).__setup__()
        t = cls.__table__()
        cls._sql_constraints = [
            ('code_uniq', Unique(t,t.code), 
            'This Request Code already exists'),
        ]

        cls._buttons.update({
            'open_support': {'invisible': Equal(Eval('state'), 'open')},
            'close_support': {'invisible': Equal(Eval('state'), 'closed')},
            })


    @classmethod
    @ModelView.button
    def open_support(cls, srs):
        cls.write(srs, {
            'state': 'open'})

    @classmethod
    @ModelView.button
    def close_support(cls, srs):
        cls.write(srs, {
            'state': 'closed'})
Example #8
0
class Template:
    __metaclass__ = PoolMeta
    __name__ = "product.template"
    purchasable = fields.Boolean('Purchasable',
                                 states={
                                     'readonly': ~Eval('active', True),
                                 },
                                 depends=['active'])
    product_suppliers = fields.One2Many(
        'purchase.product_supplier',
        'product',
        'Suppliers',
        states={
            'readonly':
            ~Eval('active', True),
            'invisible': (~Eval('purchasable', False)
                          | ~Eval('context', {}).get('company')),
        },
        depends=['active', 'purchasable'])
    purchase_uom = fields.Many2One(
        'product.uom',
        'Purchase UOM',
        states={
            'readonly': ~Eval('active'),
            'invisible': ~Eval('purchasable'),
            'required': Eval('purchasable', False),
        },
        domain=[('category', '=', Eval('default_uom_category'))],
        depends=['active', 'purchasable', 'default_uom_category'])

    @classmethod
    def __setup__(cls):
        super(Template, cls).__setup__()
        cls._error_messages.update({
            'change_purchase_uom': ('Purchase prices are based '
                                    'on the purchase uom.'),
        })
        required = ~Eval('account_category') & Eval('purchasable', False)
        if not cls.account_expense.states.get('required'):
            cls.account_expense.states['required'] = required
        else:
            cls.account_expense.states['required'] = (
                cls.account_expense.states['required'] | required)
        if 'account_category' not in cls.account_expense.depends:
            cls.account_expense.depends.append('account_category')
        if 'purchasable' not in cls.account_expense.depends:
            cls.account_expense.depends.append('purchasable')

    @fields.depends('default_uom', 'purchase_uom', 'purchasable')
    def on_change_default_uom(self):
        try:
            super(Template, self).on_change_default_uom()
        except AttributeError:
            pass
        if self.default_uom:
            if self.purchase_uom:
                if self.default_uom.category != self.purchase_uom.category:
                    self.purchase_uom = self.default_uom
            else:
                self.purchase_uom = self.default_uom

    @classmethod
    def view_attributes(cls):
        return super(Template, cls).view_attributes() + [
            ('//page[@id="suppliers"]', 'states', {
                'invisible': ~Eval('purchasable'),
            })
        ]

    @classmethod
    def write(cls, *args):
        actions = iter(args)
        for templates, values in zip(actions, actions):
            if not values.get("purchase_uom"):
                continue
            for template in templates:
                if not template.purchase_uom:
                    continue
                if template.purchase_uom.id == values["purchase_uom"]:
                    continue
                for product in template.products:
                    if not product.product_suppliers:
                        continue
                    cls.raise_user_warning('%s@product_template' % template.id,
                                           'change_purchase_uom')
        super(Template, cls).write(*args)
Example #9
0
class Journal(ModelSQL, ModelView):
    'Journal'
    __name__ = 'account.journal'
    name = fields.Char('Name', size=None, required=True, translate=True)
    code = fields.Char('Code', size=None)
    active = fields.Boolean('Active', select=True)
    type = fields.Selection('get_types', 'Type', required=True)
    view = fields.Many2One('account.journal.view', 'View')
    update_posted = fields.Boolean('Allow updating posted moves')
    sequence = fields.Property(
        fields.Many2One('ir.sequence',
                        'Sequence',
                        domain=[('code', '=', 'account.journal')],
                        context={'code': 'account.journal'},
                        states={
                            'required':
                            Bool(Eval('context', {}).get('company', -1)),
                        }))
    credit_account = fields.Property(
        fields.Many2One('account.account',
                        'Default Credit Account',
                        domain=[
                            ('kind', '!=', 'view'),
                            ('company', '=', Eval('context',
                                                  {}).get('company', -1)),
                        ],
                        states={
                            'required':
                            ((Eval('type').in_(['cash', 'write-off']))
                             & (Eval('context', {}).get('company', -1) != -1)),
                            'invisible':
                            ~Eval('context', {}).get('company', -1),
                        },
                        depends=['type']))
    debit_account = fields.Property(
        fields.Many2One('account.account',
                        'Default Debit Account',
                        domain=[
                            ('kind', '!=', 'view'),
                            ('company', '=', Eval('context',
                                                  {}).get('company', -1)),
                        ],
                        states={
                            'required':
                            ((Eval('type').in_(['cash', 'write-off']))
                             & (Eval('context', {}).get('company', -1) != -1)),
                            'invisible':
                            ~Eval('context', {}).get('company', -1),
                        },
                        depends=['type']))
    debit = fields.Function(
        fields.Numeric('Debit',
                       digits=(16, Eval('currency_digits', 2)),
                       depends=['currency_digits']),
        'get_debit_credit_balance')
    credit = fields.Function(
        fields.Numeric('Credit',
                       digits=(16, Eval('currency_digits', 2)),
                       depends=['currency_digits']),
        'get_debit_credit_balance')
    balance = fields.Function(
        fields.Numeric('Balance',
                       digits=(16, Eval('currency_digits', 2)),
                       depends=['currency_digits']),
        'get_debit_credit_balance')
    currency_digits = fields.Function(fields.Integer('Currency Digits'),
                                      'get_currency_digits')

    @classmethod
    def __setup__(cls):
        super(Journal, cls).__setup__()
        cls._order.insert(0, ('name', 'ASC'))

    @classmethod
    def __register__(cls, module_name):
        TableHandler = backend.get('TableHandler')
        super(Journal, cls).__register__(module_name)
        cursor = Transaction().connection.cursor()
        table = TableHandler(cls, module_name)

        # Migration from 1.0 sequence Many2One change into Property
        if table.column_exist('sequence'):
            Property = Pool().get('ir.property')
            sql_table = cls.__table__()
            cursor.execute(*sql_table.select(sql_table.id, sql_table.sequence))
            for journal_id, sequence_id in cursor.fetchall():
                Property.set('sequence', cls._name, journal_id,
                             (sequence_id and 'ir.sequence,' + str(sequence_id)
                              or False))
            table.drop_column('sequence', exception=True)

    @staticmethod
    def default_active():
        return True

    @staticmethod
    def default_update_posted():
        return False

    @staticmethod
    def default_sequence():
        return None

    @staticmethod
    def get_types():
        Type = Pool().get('account.journal.type')
        types = Type.search([])
        return [(x.code, x.name) for x in types]

    @classmethod
    def search_rec_name(cls, name, clause):
        if clause[1].startswith('!') or clause[1].startswith('not '):
            bool_op = 'AND'
        else:
            bool_op = 'OR'
        return [
            bool_op,
            ('code', ) + tuple(clause[1:]),
            (cls._rec_name, ) + tuple(clause[1:]),
        ]

    @classmethod
    def get_currency_digits(cls, journals, name):
        pool = Pool()
        Company = pool.get('company.company')
        company_id = Transaction().context.get('company')
        if company_id:
            company = Company(company_id)
            digits = company.currency.digits
        else:
            digits = 2
        return dict.fromkeys([j.id for j in journals], digits)

    @classmethod
    def get_debit_credit_balance(cls, journals, names):
        pool = Pool()
        MoveLine = pool.get('account.move.line')
        Move = pool.get('account.move')
        context = Transaction().context
        cursor = Transaction().connection.cursor()

        result = {}
        ids = [j.id for j in journals]
        for name in ['debit', 'credit', 'balance']:
            result[name] = dict.fromkeys(ids, 0)

        line = MoveLine.__table__()
        move = Move.__table__()
        where = ((move.date >= context['start_date'])
                 & (move.date <= context['end_date']))
        for sub_journals in grouped_slice(journals):
            sub_journals = list(sub_journals)
            red_sql = reduce_ids(move.journal, [j.id for j in sub_journals])
            accounts = None
            for journal in sub_journals:
                credit_account = (journal.credit_account.id
                                  if journal.credit_account else None)
                debit_account = (journal.debit_account.id
                                 if journal.debit_account else None)
                clause = ((move.journal == journal.id)
                          & (((line.credit != Null)
                              & (line.account == credit_account))
                             | ((line.debit != Null)
                                & (line.account == debit_account))))
                if accounts is None:
                    accounts = clause
                else:
                    accounts |= clause

            query = line.join(move, 'LEFT',
                              condition=line.move == move.id).select(
                                  move.journal,
                                  Sum(line.debit),
                                  Sum(line.credit),
                                  where=where & red_sql & accounts,
                                  group_by=move.journal)
            cursor.execute(*query)
            for journal_id, debit, credit in cursor.fetchall():
                # SQLite uses float for SUM
                if not isinstance(debit, Decimal):
                    debit = Decimal(str(debit))
                if not isinstance(credit, Decimal):
                    credit = Decimal(str(credit))
                result['debit'][journal_id] = debit
                result['credit'][journal_id] = credit
                result['balance'][journal_id] = debit - credit
        return result
Example #10
0
class WebSite(ModelSQL, ModelView):
    """
    One of the most powerful features of Nereid is the ability to
    manage multiple websites from one back-end. A web site in nereid
    represents a collection or URLs, settings.

    :param name: Name of the web site
    :param base_url: The unique URL of the website, You cannot have two
                     websites, with the same base_url
    :param url_map: The active URL Map for the website (M2O URLMap)
    :param company: The company linked with the website.
    :param active: Whether the website is active or not.

    """
    __name__ = "nereid.website"

    #: The name field is used for both information and also as
    #: the site identifier for nereid. The WSGI application requires
    #: SITE argument. The SITE argument is then used to load URLs and
    #: other settings for the website. Needs to be unique
    name = fields.Char('Name', required=True, select=True)

    #: The company to which the website belongs. Useful when creating
    #: records like sale order which require a company to be present
    company = fields.Many2One('company.company', 'Company', required=True)

    active = fields.Boolean('Active')

    #: The list of countries this website operates in. Used for generating
    #: Countries list in the registration form etc.
    countries = fields.Many2Many('nereid.website-country.country', 'website',
                                 'country', 'Countries Available')

    #: Allowed currencies in the website
    currencies = fields.Many2Many('nereid.website-currency.currency',
                                  'website', 'currency',
                                  'Currencies Available')

    #: Default locale
    default_locale = fields.Many2One('nereid.website.locale',
                                     'Default Locale',
                                     required=True)

    #: Allowed locales in the website
    locales = fields.Many2Many('nereid.website-nereid.website.locale',
                               'website', 'locale', 'Languages Available')

    #: The res.user with which the nereid application will be loaded
    #:  .. versionadded: 0.3
    application_user = fields.Many2One('res.user',
                                       'Application User',
                                       required=True)

    timezone = fields.Function(fields.Selection(
        [(x, x) for x in pytz.common_timezones], 'Timezone', translate=False),
                               getter="get_timezone")

    def get_timezone(self, name):
        warnings.warn(
            "Website timezone is deprecated, use company timezone instead",
            DeprecationWarning,
            stacklevel=2)
        return self.company.timezone

    @staticmethod
    def default_active():
        return True

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

    @staticmethod
    def default_default_locale():
        ModelData = Pool().get('ir.model.data')

        if not Pool().test:
            return ModelData.get_id("nereid", "website_locale_en-us")

    @staticmethod
    def default_application_user():
        ModelData = Pool().get('ir.model.data')
        return ModelData.get_id("nereid", "web_user")

    @classmethod
    def __setup__(cls):
        super(WebSite, cls).__setup__()
        table = cls.__table__()
        cls._sql_constraints = [
            ('name_uniq', Unique(table, table.name),
             'Another site with the same name already exists!')
        ]

    @classmethod
    @route("/countries", methods=["GET"])
    def country_list(cls):
        """
        Return the list of countries in JSON
        """
        return jsonify(result=[{
            'key': c.id,
            'value': c.name
        } for c in current_website.countries])

    @classmethod
    @route("/subdivisions", methods=["GET"])
    def subdivision_list(cls):
        """
        Return the list of states for given country
        """
        Subdivision = Pool().get('country.subdivision')

        country = int(request.args.get('country', 0))
        if country not in [c.id for c in current_website.countries]:
            abort(404)
        subdivisions = Subdivision.search([('country', '=', country)])
        return jsonify(result=[s.serialize() for s in subdivisions])

    def stats(self, **arguments):
        """
        Test method.
        """
        return u'Request: %s\nArguments: %s\nEnviron: %s\n' \
            % (request, arguments, request.environ)

    @classmethod
    @route('/')
    def home(cls):
        "A dummy home method which just renders home.jinja"
        return render_template('home.jinja')

    @classmethod
    @route('/login', methods=['GET', 'POST'])
    def login(cls):
        """
        Simple login based on the email and password

        Required post data see :class:LoginForm
        """
        login_form = LoginForm(request.form)

        if not current_user.is_anonymous and request.args.get('next'):
            return redirect(request.args['next'])

        if request.method == 'POST' and login_form.validate():
            NereidUser = Pool().get('nereid.user')
            user = NereidUser.authenticate(login_form.email.data,
                                           login_form.password.data)
            # Result can be the following:
            # 1 - Browse record of User (successful login)
            # 2 - None - Login failure without message
            # 3 - Any other false value (no message is shown. useful if you
            #       want to handle the message shown to user)
            if user:
                # NOTE: Translators leave %s as such
                flash(
                    _("You are now logged in. Welcome %(name)s",
                      name=user.display_name))
                if login_user(user, remember=login_form.remember.data):
                    if request.is_xhr:
                        return jsonify({
                            'success': True,
                            'user': user.serialize(),
                        })
                    else:
                        return redirect(
                            request.values.get('next',
                                               url_for('nereid.website.home')))
                else:
                    flash(_("Your account has not been activated yet!"))
            elif user is None:
                flash(_("Invalid login credentials"))

            failed_login.send(form=login_form)

            if request.is_xhr:
                rv = jsonify(message="Bad credentials")
                rv.status_code = 401
                return rv

        return render_template('login.jinja', login_form=login_form)

    @classmethod
    @route('/logout')
    def logout(cls):
        "Log the user out"
        logout_user()
        flash(
            _('You have been logged out successfully. Thanks for visiting us'))
        return redirect(
            request.args.get('next', url_for('nereid.website.home')))

    @classmethod
    @login_required
    @route('/login/token', methods=['POST'])
    def get_auth_token(cls):
        """
        A method that returns a login token and user information in a json
        response. This should probably be called with basic authentication in
        the header. The token generated could then be used for subsequent
        requests.
        """
        return jsonify({
            'user': current_user.serialize(),
            'token': current_user.get_auth_token(),
        })

    @staticmethod
    def account_context():
        """This fills the account context for the template
        rendering my account. Additional modules might want to fill extra
        data into the context
        """
        return dict(
            user=current_user,
            party=current_user.party,
        )

    @classmethod
    @route("/account", methods=["GET"])
    @login_required
    def account(cls):
        return render_template('account.jinja', **cls.account_context())

    def get_currencies(self):
        """Returns available currencies for current site

        .. note::
            A special method is required so that the fetch can be speeded up,
            by pushing the categories to the central cache which cannot be
            done directly on a browse node.
        """
        cache_key = key_from_list([
            Transaction().database.name,
            Transaction().user,
            'nereid.website.get_currencies',
        ])
        # The website is automatically appended to the cache prefix
        rv = cache.get(cache_key)
        if rv is None:
            rv = [{
                'id': c.id,
                'name': c.name,
                'symbol': c.symbol,
            } for c in self.currencies]
            cache.set(cache_key, rv, 60 * 60)
        return rv

    @staticmethod
    def _user_status():
        """Returns the commonly required status parameters of the user

        This method could be inherited and components could be added
        """
        rv = {
            'messages': map(unicode, get_flashed_messages()),
        }
        if current_user.is_anonymous:
            rv.update({'logged_id': False})
        else:
            rv.update({'logged_in': True, 'name': current_user.display_name})
        return rv

    @classmethod
    @route("/user_status", methods=["GET", "POST"])
    def user_status(cls):
        """
        Returns a JSON of the user_status
        """
        return jsonify(status=cls._user_status())

    @classmethod
    def get_from_host(cls, host, silent=False):
        """
        Returns the website with name as given host

        If not silent a website not found error is raised.
        """
        if cls.search([], count=True) == 1:
            return cls.search([])[0]
        try:
            website, = cls.search([('name', '=', host)])
        except ValueError:
            if not silent:
                raise WebsiteNotFound()
        else:
            return website

    def get_context(self):
        """
        Returns transaction context to be used by nereid dispatcher for this
        website
        """
        return {}

    _url_adapter_cache = Cache('nereid.website.url_adapter', context=False)

    @classmethod
    def clear_url_adapter_cache(cls, *args):
        """
        A method which conveniently clears the cache
        """
        cls._url_adapter_cache.clear()

    def get_url_adapter(self, app):
        """
        Returns the URL adapter for the website
        """
        cache_rv = self._url_adapter_cache.get(self.id)

        if cache_rv is not None:
            return cache_rv

        url_rules = app.get_urls()[:]

        # Add the static url
        url_rules.append(
            app.url_rule_class(
                app.static_url_path + '/<path:filename>',
                endpoint='static',
            ))

        url_map = Map()
        if self.locales:
            # Create the URL map with locale prefix
            url_map.add(
                app.url_rule_class(
                    '/',
                    redirect_to='/%s' % self.default_locale.code,
                ), )
            url_map.add(Submount('/<locale>', url_rules))
        else:
            # Create a new map with the given URLs
            map(url_map.add, url_rules)

        # Add the rules from the application's url map filled through the
        # route decorator or otherwise
        for rule in app.url_map._rules:
            url_map.add(rule.empty())

        self._url_adapter_cache.set(self.id, url_map)

        return url_map

    def get_current_locale(self, req):
        """
        Returns the active record of the current locale.
        The locale could either be from the URL if the locale was specified
        in the URL, or the default locale from the website.
        """
        if req.view_args and 'locale' in req.view_args:
            for locale in self.locales:
                if locale.code == req.view_args['locale']:
                    return locale

        # Return the default locale
        return self.default_locale
Example #11
0
class Dunning(ModelSQL, ModelView):
    'Account Dunning'
    __name__ = 'account.dunning'
    company = fields.Many2One(
        'company.company',
        'Company',
        required=True,
        help="Make the dunning belong to the company.",
        select=True,
        domain=[
            ('id', If(Eval('context', {}).contains('company'), '=',
                      '!='), Eval('context', {}).get('company', -1)),
        ],
        states=_STATES,
        depends=_DEPENDS)
    line = fields.Many2One('account.move.line',
                           'Line',
                           required=True,
                           help="The receivable line to dun for.",
                           domain=[
                               ('account.type.receivable', '=', True),
                               ('account.company', '=', Eval('company', -1)),
                               [
                                   'OR',
                                   ('debit', '>', 0),
                                   ('credit', '<', 0),
                               ],
                           ],
                           states=_STATES,
                           depends=_DEPENDS + ['company'])
    procedure = fields.Many2One('account.dunning.procedure',
                                'Procedure',
                                required=True,
                                states=_STATES,
                                depends=_DEPENDS)
    level = fields.Many2One('account.dunning.level',
                            'Level',
                            required=True,
                            domain=[
                                ('procedure', '=', Eval('procedure', -1)),
                            ],
                            states=_STATES,
                            depends=_DEPENDS + ['procedure'])
    blocked = fields.Boolean(
        'Blocked', help="Check to block further levels of the procedure.")
    state = fields.Selection([
        ('draft', 'Draft'),
        ('waiting', "Waiting"),
        ('final', "Final"),
    ],
                             'State',
                             readonly=True)
    active = fields.Function(fields.Boolean('Active'),
                             'get_active',
                             searcher='search_active')
    party = fields.Function(fields.Many2One('party.party', 'Party'),
                            'get_line_field',
                            searcher='search_line_field')
    amount = fields.Function(
        fields.Numeric('Amount',
                       digits=(16, Eval('currency_digits', 2)),
                       depends=['currency_digits']), 'get_amount')
    currency_digits = fields.Function(fields.Integer('Currency Digits'),
                                      'get_line_field')
    maturity_date = fields.Function(fields.Date('Maturity Date'),
                                    'get_line_field',
                                    searcher='search_line_field')
    amount_second_currency = fields.Function(
        fields.Numeric('Amount Second Currency',
                       digits=(16, Eval('second_currency_digits', 2)),
                       depends=['second_currency_digits']),
        'get_amount_second_currency')
    second_currency = fields.Function(
        fields.Many2One('currency.currency', 'Second Currency'),
        'get_second_currency')
    second_currency_digits = fields.Function(
        fields.Integer('Second Currency Digits'), 'get_second_currency_digits')

    @classmethod
    def __setup__(cls):
        super(Dunning, cls).__setup__()
        table = cls.__table__()
        cls._sql_constraints = [
            ('line_unique', Unique(table, table.line),
             'account_dunning.msg_dunning_line_unique'),
        ]
        cls._active_field = 'active'

    @classmethod
    def __register__(cls, module):
        dunning = cls.__table__()
        super().__register__(module)
        cursor = Transaction().connection.cursor()

        # Migration from 4.8: rename done state into waiting
        cursor.execute(*dunning.update([dunning.state], ['waiting'],
                                       where=dunning.state == 'done'))

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

    @staticmethod
    def default_state():
        return 'draft'

    def get_active(self, name):
        return not self.line.reconciliation

    def get_line_field(self, name):
        value = getattr(self.line, name)
        if isinstance(value, Model):
            return value.id
        else:
            return value

    @classmethod
    def search_line_field(cls, name, clause):
        return [('line.' + clause[0], ) + tuple(clause[1:])]

    def get_amount(self, name):
        return self.line.debit - self.line.credit

    def get_amount_second_currency(self, name):
        amount = self.line.debit - self.line.credit
        if self.line.amount_second_currency:
            return self.line.amount_second_currency.copy_sign(amount)
        else:
            return amount

    def get_second_currency(self, name):
        if self.line.second_currency:
            return self.line.second_currency.id
        else:
            return self.line.account.company.currency.id

    def get_second_currency_digits(self, name):
        if self.line.second_currency:
            return self.line.second_currency.digits
        else:
            return self.line.account.company.currency.digits

    @classmethod
    def search_active(cls, name, clause):
        reverse = {
            '=': '!=',
            '!=': '=',
        }
        if clause[1] in reverse:
            if clause[2]:
                return [('line.reconciliation', clause[1], None)]
            else:
                return [('line.reconciliation', reverse[clause[1]], None)]
        else:
            return []

    @classmethod
    def _overdue_line_domain(cls, date):
        return [
            ('account.type.receivable', '=', True),
            ('dunnings', '=', None),
            ('maturity_date', '<=', date),
            [
                'OR',
                ('debit', '>', 0),
                ('credit', '<', 0),
            ],
            ('party', '!=', None),
            ('reconciliation', '=', None),
        ]

    @classmethod
    def generate_dunnings(cls, date=None):
        pool = Pool()
        Date = pool.get('ir.date')
        MoveLine = pool.get('account.move.line')

        if date is None:
            date = Date.today()

        set_level = defaultdict(list)
        for dunning in cls.search([
            ('state', '=', 'waiting'),
            ('blocked', '=', False),
        ]):
            procedure = dunning.procedure
            levels = procedure.levels
            levels = levels[levels.index(dunning.level) + 1:]
            if levels:
                for level in levels:
                    if level.test(dunning.line, date):
                        break
                else:
                    level = dunning.level
                if level != dunning.level:
                    set_level[level].append(dunning)
            else:
                set_level[None].append(dunning)
        to_write = []
        for level, dunnings in set_level.items():
            if level:
                to_write.extend((dunnings, {
                    'level': level.id,
                    'state': 'draft',
                }))
            else:
                to_write.extend((dunnings, {
                    'state': 'final',
                }))
        if to_write:
            cls.write(*to_write)

        lines = MoveLine.search(cls._overdue_line_domain(date))
        dunnings = (cls._get_dunning(line, date) for line in lines)
        cls.save([d for d in dunnings if d])

    @classmethod
    def _get_dunning(cls, line, date):
        procedure = line.dunning_procedure
        if not procedure:
            return
        for level in procedure.levels:
            if level.test(line, date):
                break
        else:
            return
        return cls(
            line=line,
            procedure=procedure,
            level=level,
        )

    @classmethod
    def process(cls, dunnings):
        cls.write(
            [d for d in dunnings if not d.blocked and d.state == 'draft'], {
                'state': 'waiting',
            })
Example #12
0
class Sale:
    "Sale"
    __name__ = 'sale.sale'

    is_ups_shipping = fields.Function(
        fields.Boolean('Is Shipping', readonly=True), 'get_is_ups_shipping')
    ups_service_type = fields.Many2One(
        'ups.service',
        'UPS Service Type',
    )
    ups_package_type = fields.Selection(UPS_PACKAGE_TYPES,
                                        'Package Content Type')
    ups_saturday_delivery = fields.Boolean("Is Saturday Delivery")

    def _get_weight_uom(self):
        """
        Returns uom for ups
        """
        UPSConfiguration = Pool().get('ups.configuration')

        weight_uom = UPSConfiguration(1).weight_uom

        if self.is_ups_shipping and weight_uom:
            return weight_uom

        return super(Sale, self)._get_weight_uom()

    @classmethod
    def __setup__(cls):
        super(Sale, cls).__setup__()
        cls._buttons.update({
            'update_ups_shipment_cost': {
                'invisible': Eval('state') != 'quotation'
            }
        })

    @staticmethod
    def default_ups_package_type():
        Config = Pool().get('sale.configuration')
        config = Config(1)
        return config.ups_package_type

    @staticmethod
    def default_ups_service_type():
        Config = Pool().get('sale.configuration')
        config = Config(1)
        return config.ups_service_type and config.ups_service_type.id or None

    @staticmethod
    def default_ups_saturday_delivery():
        return False

    def on_change_lines(self):
        """Pass a flag in context which indicates the get_sale_price method
        of ups carrier not to calculate cost on each line change
        """
        with Transaction().set_context({'ignore_carrier_computation': True}):
            return super(Sale, self).on_change_lines()

    def get_is_ups_shipping(self, name):
        """
        Check if shipping is from UPS
        """
        return self.carrier and self.carrier.carrier_cost_method == 'ups'

    def _get_carrier_context(self):
        "Pass sale in the context"
        context = super(Sale, self)._get_carrier_context()

        if not self.carrier.carrier_cost_method == 'ups':
            return context

        context = context.copy()
        context['sale'] = self.id
        return context

    def apply_ups_shipping(self):
        "Add a shipping line to sale for ups"
        Sale = Pool().get('sale.sale')
        Currency = Pool().get('currency.currency')

        if self.is_ups_shipping:
            with Transaction().set_context(self._get_carrier_context()):
                shipment_cost, currency_id = self.carrier.get_sale_price()
                if not shipment_cost:
                    return
            # Convert the shipping cost to sale currency from USD
            shipment_cost = Currency.compute(Currency(currency_id),
                                             shipment_cost, self.currency)
            Sale.write(
                [self],
                {
                    'lines': [
                        (
                            'create',
                            [{
                                'type': 'line',
                                'product': self.carrier.carrier_product.id,
                                'description': self.ups_service_type.name,
                                'quantity': 1,  # XXX
                                'unit':
                                self.carrier.carrier_product.sale_uom.id,
                                'unit_price': shipment_cost,
                                'shipment_cost': shipment_cost,
                                'amount': shipment_cost,
                                'taxes': [],
                                'sequence': 9999,  # XXX
                            }]),
                        ('delete',
                         [line for line in self.lines if line.shipment_cost]),
                    ]
                })

    @classmethod
    def quote(cls, sales):
        res = super(Sale, cls).quote(sales)
        cls.update_ups_shipment_cost(sales)
        return res

    @classmethod
    @ModelView.button
    def update_ups_shipment_cost(cls, sales):
        "Updates the shipping line with new value if any"
        for sale in sales:
            sale.apply_ups_shipping()

    def _update_ups_shipments(self):
        """
        Update shipments with ups data
        """
        Shipment = Pool().get('stock.shipment.out')

        assert self.is_ups_shipping

        shipments = list(self.shipments)
        Shipment.write(
            shipments, {
                'ups_service_type': self.ups_service_type.id,
                'ups_package_type': self.ups_package_type,
                'ups_saturday_delivery': self.ups_saturday_delivery,
            })

    def create_shipment(self, shipment_type):
        """
        Create shipments for sale
        """
        with Transaction().set_context(ignore_carrier_computation=True):
            # disable `carrier cost computation`(default behaviour) as cost
            # should only be computed after updating service_type else error may
            # occur, with improper ups service_type.
            shipments = super(Sale, self).create_shipment(shipment_type)

        if shipment_type == 'out' and shipments and self.is_ups_shipping:
            self._update_ups_shipments()
        return shipments

    def _get_ups_packages(self):
        """
        Return UPS Packages XML
        """
        UPSConfiguration = Pool().get('ups.configuration')

        ups_config = UPSConfiguration(1)

        package_type = RatingService.packaging_type(Code=self.ups_package_type)

        weight = self._get_package_weight(ups_config.weight_uom).quantize(
            Decimal('.01'), rounding=ROUND_UP)
        package_weight = RatingService.package_weight_type(
            Weight=str(weight),
            Code=ups_config.weight_uom_code,
        )
        package_service_options = RatingService.package_service_options_type(
            RatingService.insured_value_type(MonetaryValue='0'))
        package_container = RatingService.package_type(
            package_type, package_weight, package_service_options)
        return [package_container]

    def _get_ship_from_address(self):
        """
        Usually the warehouse from which you ship
        """
        return self.warehouse.address

    def _get_rate_request_xml(self, mode='rate'):
        """
        Return the E builder object with the rate fetching request

        :param mode: 'rate' - to fetch rate of current shipment and selected
                              package type
                     'shop' - to get a rates list
        """
        UPSConfiguration = Pool().get('ups.configuration')

        ups_config = UPSConfiguration(1)

        assert mode in ('rate', 'shop'), "Mode should be 'rate' or 'shop'"

        if mode == 'rate' and not self.ups_service_type:
            self.raise_user_error('ups_service_type_missing')

        shipment_args = self._get_ups_packages()

        shipment_args.extend([
            self.warehouse.address.to_ups_shipper(),  # Shipper
            self.shipment_address.to_ups_to_address(),  # Ship to
            self._get_ship_from_address().to_ups_from_address(),  # Ship from
        ])

        if ups_config.negotiated_rates:
            shipment_args.append(
                RatingService.rate_information_type(negotiated=True))

        if mode == 'rate':
            # TODO: handle ups_saturday_delivery
            shipment_args.append(
                RatingService.service_type(Code=self.ups_service_type.code))
            request_option = E.RequestOption('Rate')
        else:
            request_option = E.RequestOption('Shop')

        return RatingService.rating_request_type(E.Shipment(*shipment_args),
                                                 RequestOption=request_option)

    def _get_ups_rate_from_rated_shipment(cls, rated_shipment):
        """
        The rated_shipment is an xml container in the response which has the
        standard rates and negotiated rates. This method should extract the
        value and return it with the currency
        """
        Currency = Pool().get('currency.currency')
        UPSConfiguration = Pool().get('ups.configuration')

        ups_config = UPSConfiguration(1)

        currency, = Currency.search([
            ('code', '=', str(rated_shipment.TotalCharges.CurrencyCode))
        ])
        if ups_config.negotiated_rates and \
                hasattr(rated_shipment, 'NegotiatedRates'):
            # If there are negotiated rates return that instead
            charges = rated_shipment.NegotiatedRates.NetSummaryCharges
            charges = currency.round(
                Decimal(str(charges.GrandTotal.MonetaryValue)))
        else:
            charges = currency.round(
                Decimal(str(rated_shipment.TotalCharges.MonetaryValue)))
        return charges, currency

    def get_ups_shipping_cost(self):
        """Returns the calculated shipping cost as sent by ups

        :returns: The shipping cost with currency
        """
        UPSConfiguration = Pool().get('ups.configuration')
        Carrier = Pool().get('carrier')

        ups_config = UPSConfiguration(1)
        carrier, = Carrier.search(['carrier_cost_method', '=', 'ups'])

        rate_request = self._get_rate_request_xml()
        rate_api = ups_config.api_instance(call="rate")

        # Instead of shopping for rates, just get a price for the given
        # service and package type to the destination we know.
        rate_api.RequestOption = E.RequestOption('Rate')

        # Logging.
        logger.debug('Making Rate API Request for shipping cost of'
                     'Sale ID: {0} and Carrier ID: {1}'.format(
                         self.id, carrier.id))
        logger.debug('--------RATE API REQUEST--------')
        logger.debug(str(rate_request))
        logger.debug('--------END REQUEST--------')

        try:
            response = rate_api.request(rate_request)
        except PyUPSException, e:
            self.raise_user_error(unicode(e[0]))

        # Logging.
        logger.debug('--------RATE API RESPONSE--------')
        logger.debug(str(response))
        logger.debug('--------END RESPONSE--------')

        shipment_cost, currency = self._get_ups_rate_from_rated_shipment(
            response.RatedShipment)
        return shipment_cost, currency.id
Example #13
0
class Connection(ModelSingleton, ModelSQL, ModelView):
    "LDAP Connection"
    __name__ = 'ldap.connection'
    _rec_name = 'server'
    server = fields.Char('Server', required=True, help='LDAP server name')
    port = fields.Integer('Port', required=True, help='LDAP server port')
    secure = fields.Selection([
        ('never', 'Never'),
        ('ssl', 'SSL'),
        ('tls', 'TLS'),
    ],
                              'Secure',
                              required=True,
                              help='LDAP secure connection')
    bind_dn = fields.Char('Bind DN', help='LDAP DN used to bind')
    bind_pass = fields.Char('Bind Pass',
                            states={
                                'required': Bool(Eval('bind_dn')),
                                'readonly': ~Eval('bind_dn'),
                            },
                            help='LDAP password used to bind',
                            depends=['bind_dn'])
    uri = fields.Function(fields.Char('URI'), 'get_uri')
    active_directory = fields.Boolean('Active Directory')

    @classmethod
    def __setup__(cls):
        super(Connection, cls).__setup__()
        cls._buttons.update({
            'test_connection': {},
        })

    @staticmethod
    def default_port():
        return 389

    @staticmethod
    def default_secure():
        return 'never'

    @staticmethod
    def default_active_directory():
        return False

    @fields.depends('secure')
    def on_change_secure(self):
        res = {}
        if self.secure in ('never', 'tls'):
            res['port'] = self.default_port()
        elif self.secure == 'ssl':
            res['port'] = 636
        return res

    def get_uri(self, name):
        return ((self.secure == 'ssl' and 'ldaps' or 'ldap') + '://%s:%s/' %
                (self.server, self.port))

    @classmethod
    @ModelView.button_action('ldap_connection.wizard_test_connection')
    def test_connection(cls, connections):
        pass

    @classmethod
    def write(cls, *args):
        actions = iter(args)
        args = []
        for connections, values in zip(actions, actions):
            if 'bind_dn' in values and not values['bind_dn']:
                values = values.copy()
                values['bind_pass'] = None
            args.extend((connections, values))
        return super(Connection, cls).write(*args)
Example #14
0
class StockShipmentOut:
    """Stock Shipment Out

    Add a field for tracking number
    """
    __name__ = 'stock.shipment.out'

    #: Indicates if the tracking information has been exported
    #: to magento. Tracking info means carrier and tracking number info
    #: which is different from exporting shipment status to magento
    is_tracking_exported_to_magento = fields.Boolean(
        'Is Tracking Info Exported To Magento'
    )
    #: The magento increment id for this shipment. This is filled when a
    #: shipment is created corresponding to the shipment to tryton
    #: in magento.
    magento_increment_id = fields.Char(
        "Magento Increment ID", readonly=True
    )

    @staticmethod
    def default_is_tracking_exported_to_magento():
        return False

    def export_tracking_info_to_magento(self):
        """
        Export tracking info to magento for the specified shipment.

        :param shipment: Browse record of shipment
        :return: Shipment increment ID
        """
        MagentoCarrier = Pool().get('magento.instance.carrier')
        Channel = Pool().get('sale.channel')
        Shipment = Pool().get('stock.shipment.out')

        channel = Channel.get_current_magento_channel()

        assert self.tracking_number
        assert self.carrier

        try:
            carrier, = MagentoCarrier.search([
                ('channel', '=', channel.id),
                ('carrier', '=', self.carrier.id)
            ])
        except ValueError:
            # No mapping carrier found use custom
            code, title = 'custom', self.carrier.rec_name
        else:
            code, title = carrier.get_magento_mapping()

        # Add tracking info to the shipment on magento
        with magento.Shipment(
            channel.magento_url, channel.magento_api_user,
            channel.magento_api_key
        ) as shipment_api:
            shipment_increment_id = shipment_api.addtrack(
                self.magento_increment_id, code, title, self.tracking_number
            )

            Shipment.write([self], {
                'is_tracking_exported_to_magento': True
            })

        return shipment_increment_id
Example #15
0
class HrContract(ModelSQL, ModelView):
    """Employee Contract"""

    __name__ = 'hr.contract'

    salary_code = fields.Char('Salary Code', required=True)
    employee = fields.Many2One('company.employee', 'Employee', required=True)
    name = fields.Char('Salary detail Reference', required=True)
    center = fields.Many2One('gnuhealth.institution', 'Center')
    department = fields.Many2One('company.department',
                                 'Department',
                                 required=True)
    designation = fields.Many2One('employee.designation',
                                  'Designation',
                                  required=True)
    date_start = fields.Date('Start Date', required=True)
    date_end = fields.Date('End Date')
    notes = fields.Text('Notes')
    is_active = fields.Boolean('Active')
    basic = fields.Float('Basic Pay', required=True)
    approve_date = fields.Date('Date of Approval')
    approve_by = fields.Many2One('res.user', 'Approved By')

    @classmethod
    def validate(cls, records):
        super(HrContract, cls).validate(records)
        for record in records:
            record.valid_date()
            contracts = cls.search([('id', '!=', record.id),
                                    ('employee', '=', record.employee),
                                    ('date_start', '<=', record.date_start),
                                    ('date_end', '>=', record.date_start)])
        if contracts:
            cls.raise_user_error('Contract for this user already\
                    exists for the given period')

    def valid_date(self):
        if self.date_end and self.date_end < self.date_start:
            self.raise_user_error('Not a valid date')

    @fields.depends('date_end')
    def on_change_with_is_active(self):
        present_date = datetime.date.today()
        if self.date_end and (present_date > self.date_end):
            return False
        return True

    @classmethod
    def set_approvedby(cls, hrcontract):
        '''
        Fill the approved by and approve date field
        '''
        approve_date = datetime.datetime.now().date()
        pool = Pool()
        User = pool.get('res.user')
        user = User(Transaction().user)
        for contract in hrcontract:
            contract.approve_date = approve_date
            contract.approve_by = user.id
        cls.save(hrcontract)

    @fields.depends('employee')
    def on_change_employee(self):
        if self.employee:
            self.salary_code = self.employee.salary_code
            self.designation = self.employee.designation
            self.department = self.employee.department
            self.center = self.employee.center

    @staticmethod
    def default_employee():
        pool = Pool()
        User = pool.get('res.user')
        user = User(Transaction().user)
        employee = user.employee
        return employee.id if employee else None

    @classmethod
    def default_date_start(cls):
        start_date = datetime.date.today().replace(day=1)
        return start_date
Example #16
0
class JournalPeriod(ModelSQL, ModelView):
    'Journal - Period'
    __name__ = 'account.journal.period'
    name = fields.Char('Name', size=None, required=True)
    journal = fields.Many2One('account.journal',
                              'Journal',
                              required=True,
                              ondelete='CASCADE',
                              states=STATES,
                              depends=DEPENDS)
    period = fields.Many2One('account.period',
                             'Period',
                             required=True,
                             ondelete='CASCADE',
                             states=STATES,
                             depends=DEPENDS)
    icon = fields.Function(fields.Char('Icon'), 'get_icon')
    active = fields.Boolean('Active',
                            select=True,
                            states=STATES,
                            depends=DEPENDS)
    state = fields.Selection([
        ('open', 'Open'),
        ('close', 'Close'),
    ],
                             'State',
                             readonly=True,
                             required=True)

    @classmethod
    def __setup__(cls):
        super(JournalPeriod, cls).__setup__()
        t = cls.__table__()
        cls._sql_constraints += [
            ('journal_period_uniq', Unique(t, t.journal, t.period),
             'You can only open one journal per period.'),
        ]
        cls._order.insert(0, ('name', 'ASC'))
        cls._error_messages.update({
            'modify_del_journal_period':
            ('You can not modify/delete '
             'journal - period "%s" because it has moves.'),
            'create_journal_period':
            ('You can not create a '
             'journal - period on closed period "%s".'),
            'open_journal_period':
            ('You can not open '
             'journal - period "%(journal_period)s" because period '
             '"%(period)s" is closed.'),
        })

    @staticmethod
    def default_active():
        return True

    @staticmethod
    def default_state():
        return 'open'

    def get_icon(self, name):
        return _ICONS.get(self.state, '')

    @classmethod
    def _check(cls, periods):
        Move = Pool().get('account.move')
        for period in periods:
            moves = Move.search([
                ('journal', '=', period.journal.id),
                ('period', '=', period.period.id),
            ],
                                limit=1)
            if moves:
                cls.raise_user_error('modify_del_journal_period',
                                     (period.rec_name, ))

    @classmethod
    def create(cls, vlist):
        Period = Pool().get('account.period')
        for vals in vlist:
            if vals.get('period'):
                period = Period(vals['period'])
                if period.state == 'close':
                    cls.raise_user_error('create_journal_period',
                                         (period.rec_name, ))
        return super(JournalPeriod, cls).create(vlist)

    @classmethod
    def write(cls, *args):
        actions = iter(args)
        for journal_periods, values in zip(actions, actions):
            if (values != {'state': 'close'} and values != {'state': 'open'}):
                cls._check(journal_periods)
            if values.get('state') == 'open':
                for journal_period in journal_periods:
                    if journal_period.period.state == 'close':
                        cls.raise_user_error(
                            'open_journal_period', {
                                'journal_period': journal_period.rec_name,
                                'period': journal_period.period.rec_name,
                            })
        super(JournalPeriod, cls).write(*args)

    @classmethod
    def delete(cls, periods):
        cls._check(periods)
        super(JournalPeriod, cls).delete(periods)

    @classmethod
    def close(cls, periods):
        '''
        Close journal - period
        '''
        cls.write(periods, {
            'state': 'close',
        })

    @classmethod
    def open_(cls, periods):
        "Open journal - period"
        cls.write(periods, {
            'state': 'open',
        })
Example #17
0
class Equipment(ModelSQL, ModelView):
    'Equipment'
    __name__ = 'lims.equipment'

    template = fields.Many2One('lims.equipment.template',
                               'Template',
                               required=True)
    name = fields.Char('Name', required=True)
    type = fields.Function(fields.Many2One('lims.equipment.type', 'Type'),
                           'get_type',
                           searcher='search_type')
    brand = fields.Function(fields.Many2One('lims.brand', 'Brand'),
                            'get_brand',
                            searcher='search_brand')
    model = fields.Char('Model', required=True)
    power = fields.Char('Power')
    voltage = fields.Char('Primary Voltage')
    voltage_secondary = fields.Char('Secondary Voltage')
    amperage = fields.Char('Secondary Amperage')
    serial_number = fields.Char('Serial number')
    internal_id = fields.Char('Internal ID Code')
    latitude = fields.Numeric('Latitude', digits=(3, 14))
    longitude = fields.Numeric('Longitude', digits=(4, 14))
    plant = fields.Many2One(
        'lims.plant',
        'Plant',
        required=True,
        select=True,
        domain=[
            If(
                Eval('context', {}).contains('party'),
                ('party', '=', Eval('context', {}).get('party', -1)), ())
        ])
    components = fields.One2Many('lims.component', 'equipment', 'Components')
    year_manufacturing = fields.Integer('Year of manufacturing')
    year_service_start = fields.Integer('Year of service start')
    internal_location = fields.Char('Internal location')
    contacts = fields.One2Many('party.address',
                               'equipment',
                               'Contacts',
                               domain=[('party', '=', Eval('party'))],
                               context={'plant': Eval('plant')},
                               depends=['party', 'plant'])
    party = fields.Function(fields.Many2One('party.party', 'Party'),
                            'get_party',
                            searcher='search_party')
    missing_data = fields.Boolean('Missing data')

    @classmethod
    def __setup__(cls):
        super().__setup__()
        cls._order.insert(0, ('template', 'ASC'))
        cls._order.insert(1, ('name', 'ASC'))
        t = cls.__table__()
        cls._sql_constraints = [
            ('name_unique', Unique(t, t.plant, t.name),
             'lims_industry.msg_equipment_name_unique'),
        ]

    @classmethod
    def create(cls, vlist):
        TaskTemplate = Pool().get('lims.administrative.task.template')
        equipments = super().create(vlist)
        TaskTemplate.create_tasks('equipment_missing_data',
                                  cls._for_task_missing_data(equipments))
        return equipments

    @classmethod
    def _for_task_missing_data(cls, equipments):
        AdministrativeTask = Pool().get('lims.administrative.task')
        res = []
        for equipment in equipments:
            if not equipment.missing_data:
                continue
            if AdministrativeTask.search([
                ('type', '=', 'equipment_missing_data'),
                ('origin', '=', '%s,%s' % (cls.__name__, equipment.id)),
                ('state', 'not in', ('done', 'discarded')),
            ]):
                continue
            res.append(equipment)
        return res

    def get_rec_name(self, name):
        res = '%s [%s]' % (self.name, self.plant.name)
        return res

    @classmethod
    def search_rec_name(cls, name, clause):
        return [
            'OR',
            ('name', ) + tuple(clause[1:]),
            ('serial_number', ) + tuple(clause[1:]),
            ('brand.name', ) + tuple(clause[1:]),
            ('plant.name', ) + tuple(clause[1:]),
            ('components.customer_description', ) + tuple(clause[1:]),
        ]

    @fields.depends('plant', '_parent_plant.party')
    def on_change_with_party(self, name=None):
        return self.get_party([self], name)[self.id]

    @classmethod
    def get_party(cls, equipments, name):
        result = {}
        for e in equipments:
            result[e.id] = e.plant and e.plant.party.id or None
        return result

    @classmethod
    def search_party(cls, name, clause):
        return [('plant.party', ) + tuple(clause[1:])]

    @fields.depends('template', '_parent_template.type')
    def on_change_with_type(self, name=None):
        return self.get_type([self], name)[self.id]

    @classmethod
    def get_type(cls, equipments, name):
        result = {}
        for e in equipments:
            result[e.id] = e.template and e.template.type.id or None
        return result

    @classmethod
    def search_type(cls, name, clause):
        return [('template.type', ) + tuple(clause[1:])]

    @fields.depends('template', '_parent_template.brand')
    def on_change_with_brand(self, name=None):
        return self.get_brand([self], name)[self.id]

    @classmethod
    def get_brand(cls, equipments, name):
        result = {}
        for e in equipments:
            result[e.id] = e.template and e.template.brand.id or None
        return result

    @classmethod
    def search_brand(cls, name, clause):
        return [('template.brand', ) + tuple(clause[1:])]

    @fields.depends('template', 'components')
    def on_change_template(self):
        pool = Pool()
        Component = pool.get('lims.component')

        if not self.template:
            return
        current_components_ids = [
            (component.kind.id, component.location and component.location.id
             or None) for component in self.components
        ]
        components = list(self.components)
        for record in self.template.component_kinds:
            kind_id = record.kind.id
            location_id = record.location and record.location.id or None
            if (kind_id, location_id) in current_components_ids:
                continue
            value = Component(**Component.default_get(
                list(Component._fields.keys()), with_rec_name=False))
            value.kind = kind_id
            value.location = location_id
            components.append(value)
        self.model = self.template.model
        self.power = self.template.power
        self.components = components

    @classmethod
    def copy(cls, records, default=None):
        if default is None:
            default = {}
        current_default = default.copy()

        new_records = []
        for record in records:
            current_default['name'] = '%s (copy)' % record.name
            new_record, = super().copy([record], default=current_default)
            new_records.append(new_record)
        return new_records
Example #18
0
class MoveLineTemplate(ModelSQL, ModelView):
    'Account Move Line Template'
    __name__ = 'account.move.line.template'
    move = fields.Many2One('account.move.template', 'Move', required=True)
    operation = fields.Selection([
        ('debit', 'Debit'),
        ('credit', 'Credit'),
    ],
                                 'Operation',
                                 required=True)
    amount = fields.Char(
        'Amount',
        required=True,
        help="A python expression that will be evaluated with the keywords.")
    account = fields.Many2One('account.account',
                              'Account',
                              required=True,
                              domain=[
                                  ('kind', '!=', 'view'),
                                  ('company', '=', Eval('_parent_move',
                                                        {}).get('company',
                                                                -1)),
                              ])
    party = fields.Char('Party',
                        states={
                            'required': Eval('party_required', False),
                            'invisible': ~Eval('party_required', False),
                        },
                        depends=['party_required'],
                        help="The name of the 'Party' keyword.")
    party_required = fields.Function(fields.Boolean('Party Required'),
                                     'on_change_with_party_required')
    description = fields.Char(
        'Description',
        help="Keywords values substitutions are identified "
        "by braces ('{' and '}').")
    taxes = fields.One2Many('account.tax.line.template', 'line', 'Taxes')

    @fields.depends('account')
    def on_change_with_party_required(self, name=None):
        if self.account:
            return self.account.party_required
        return False

    def get_line(self, values):
        'Return the move line for the keyword values'
        pool = Pool()
        Line = pool.get('account.move.line')
        Keyword = pool.get('account.move.template.keyword')

        line = Line()
        amount = simple_eval(decistmt(self.amount),
                             functions={'Decimal': Decimal},
                             names=values)
        amount = self.move.company.currency.round(amount)
        if self.operation == 'debit':
            line.debit = amount
        else:
            line.credit = amount
        line.account = self.account
        if self.party:
            line.party = values.get(self.party)
        if self.description:
            line.description = self.description.format(
                **dict(Keyword.format_values(self.move, values)))
        line.tax_lines = [t.get_line(values) for t in self.taxes]

        return line
Example #19
0
class Ambulance (ModelSQL, ModelView):
    'Ambulance'
    __name__ = 'gnuhealth.ambulance'

    vehicle_identifier = fields.Char('ID', required=True,
        help="Ambulance license number or other type of ID")

    vehicle_brand = fields.Char('Brand', help="Ambulance maker")
    vehicle_model = fields.Char('Model', help="Ambulance model")

    vehicle_odometer = fields.Integer('Odometer',
        help="Current odometer reading")

    vehicle_type = fields.Selection([
        (None, ''),
        ('van', 'Van'),
        ('car', 'Car'),
        ('boat', 'Boat'),
        ('helicopter', 'Helicopter'),
        ('airplane', 'Airplane'),
        ('motorcycle', 'Motorcycle'),
        ('bicycle', 'Bicycle'),
        ('drone', 'Drone'),
        ], 'Type', required=True,
        help="Type of vehicle",sort=False)

    vehicle_function = fields.Selection([
        (None, ''),
        ('patient_transport', 'Type A - Patient Transport'),
        ('emergency', 'Type B - Emergency'),
        ('icu', 'Type C - Mobile ICU'),
        ], 'Function',sort=False, required=True, 
        help="Vehicle main functionality")
    
    vehicle_station = fields.Many2One(
        'gnuhealth.institution', 'Station',
        help="Station / Base of the vehicle")

    state = fields.Selection([
        (None, ''),
        ('available', 'Available / At Station'),
        ('dispatched', 'Dispatched'),
        ('en_route', 'En Route'),
        ('on_location', 'On Location'),
        ('to_hospital', 'To Hospital'),
        ('at_hospital', 'At Hospital'),
        ('returning', 'Returning'),
        ('out_of_service', 'Out of service'),
        ], 'Status',sort=False, readonly=True, help="Vehicle status")

    vehicle_remarks = fields.Text('Remarks')

    active = fields.Boolean('Active', select=True)

    @staticmethod
    def default_active():
        return True

    @staticmethod
    def default_state():
        return 'available'

    @classmethod
    def __setup__(cls):
        super(Ambulance, cls).__setup__()
        t = cls.__table__()
        cls._sql_constraints = [
            ('vehicle_uniq', Unique(t,t.vehicle_identifier), 
            'This vehicle ID already exists'),
        ]

    def get_rec_name(self, name):
        return (self.vehicle_identifier + ' : ' + self.vehicle_type)
Example #20
0
class MoveTemplateKeyword(sequence_ordered(), ModelSQL, ModelView):
    'Account Move Template Keyword'
    __name__ = 'account.move.template.keyword'
    name = fields.Char('Name', required=True)
    string = fields.Char('String', required=True, translate=True)
    move = fields.Many2One('account.move.template', 'Move', required=True)
    type_ = fields.Selection([
        ('char', 'Char'),
        ('numeric', 'Numeric'),
        ('date', 'Date'),
        ('party', 'Party'),
    ], 'Type')
    required = fields.Boolean('Required')
    digits = fields.Integer('Digits',
                            states={
                                'invisible': Eval('type_') != 'numeric',
                                'required': Eval('type_') == 'numeric',
                            },
                            depends=['type_'])

    @staticmethod
    def default_required():
        return False

    def get_field(self):
        field = getattr(self, '_get_field_%s' % self.type_)()
        field.update({
            'name': self.name,
            'string': self.string,
            'required': self.required,
        })
        return field

    def _get_field_char(self):
        return {'type': 'char'}

    def _get_field_numeric(self):
        return {'type': 'numeric', 'digits': (16, self.digits)}

    def _format_numeric(self, lang, value):
        if value:
            return lang.format('%.*f', (self.digits, value), True)
        else:
            return ''

    def _get_field_date(self):
        return {'type': 'date'}

    def _format_date(self, lang, value):
        if value:
            return lang.strftime(value)
        else:
            return ''

    def _get_field_party(self):
        return {
            'type': 'many2one',
            'relation': 'party.party',
        }

    def _format_party(self, lang, value):
        pool = Pool()
        Party = pool.get('party.party')
        if value:
            return Party(value).rec_name
        else:
            return ''

    @staticmethod
    def format_values(template, values):
        "Yield key and formatted value"
        pool = Pool()
        Lang = pool.get('ir.lang')

        lang, = Lang.search([
            ('code', '=', Transaction().language),
        ])
        keywords = {k.name: k for k in template.keywords}

        for k, v in values.iteritems():
            keyword = keywords[k]
            func = getattr(keyword, '_format_%s' % keyword.type_, None)
            if func:
                yield k, func(lang, v)
            else:
                yield k, v
Example #21
0
class ResultsReportVersionDetailSample(metaclass=PoolMeta):
    __name__ = 'lims.results_report.version.detail.sample'

    plant = fields.Function(fields.Many2One('lims.plant', 'Plant'),
                            'get_notebook_field')
    equipment = fields.Function(fields.Many2One('lims.equipment', 'Equipment'),
                                'get_notebook_field')
    equipment_template = fields.Function(
        fields.Many2One('lims.equipment.template', 'Equipment Template'),
        'get_notebook_field')
    equipment_model = fields.Function(fields.Char('Equipment Model'),
                                      'get_notebook_field')
    equipment_serial_number = fields.Function(
        fields.Char('Equipment Serial Number'), 'get_notebook_field')
    equipment_name = fields.Function(fields.Char('Equipment Name'),
                                     'get_notebook_field')
    component = fields.Function(fields.Many2One('lims.component', 'Component'),
                                'get_notebook_field')
    comercial_product = fields.Function(
        fields.Many2One('lims.comercial.product', 'Comercial Product'),
        'get_notebook_field')
    precedent1 = fields.Many2One(
        'lims.notebook',
        'Precedent 1',
        domain=[
            If(~Eval('free_precedents'),
               [('component', '=', Eval('component')),
                ('fraction.sample.state', '!=', 'annulled')],
               [('fraction.sample.state', '!=', 'annulled')])
        ],
        depends=['free_precedents', 'component'])
    precedent2 = fields.Many2One(
        'lims.notebook',
        'Precedent 2',
        domain=[
            If(~Eval('free_precedents'),
               [('component', '=', Eval('component')),
                ('fraction.sample.state', '!=', 'annulled')],
               [('fraction.sample.state', '!=', 'annulled')])
        ],
        depends=['free_precedents', 'component'])
    precedent3 = fields.Many2One(
        'lims.notebook',
        'Precedent 3',
        domain=[
            If(~Eval('free_precedents'),
               [('component', '=', Eval('component')),
                ('fraction.sample.state', '!=', 'annulled')],
               [('fraction.sample.state', '!=', 'annulled')])
        ],
        depends=['free_precedents', 'component'])
    precedent4 = fields.Many2One(
        'lims.notebook',
        'Precedent 4',
        domain=[
            If(~Eval('free_precedents'),
               [('component', '=', Eval('component')),
                ('fraction.sample.state', '!=', 'annulled')],
               [('fraction.sample.state', '!=', 'annulled')])
        ],
        depends=['free_precedents', 'component'])
    precedent5 = fields.Many2One(
        'lims.notebook',
        'Precedent 5',
        domain=[
            If(~Eval('free_precedents'),
               [('component', '=', Eval('component')),
                ('fraction.sample.state', '!=', 'annulled')],
               [('fraction.sample.state', '!=', 'annulled')])
        ],
        depends=['free_precedents', 'component'])
    precedent6 = fields.Many2One(
        'lims.notebook',
        'Precedent 6',
        domain=[
            If(~Eval('free_precedents'),
               [('component', '=', Eval('component')),
                ('fraction.sample.state', '!=', 'annulled')],
               [('fraction.sample.state', '!=', 'annulled')])
        ],
        depends=['free_precedents', 'component'])
    precedent7 = fields.Many2One(
        'lims.notebook',
        'Precedent 7',
        domain=[
            If(~Eval('free_precedents'),
               [('component', '=', Eval('component')),
                ('fraction.sample.state', '!=', 'annulled')],
               [('fraction.sample.state', '!=', 'annulled')])
        ],
        depends=['free_precedents', 'component'])
    precedent8 = fields.Many2One(
        'lims.notebook',
        'Precedent 8',
        domain=[
            If(~Eval('free_precedents'),
               [('component', '=', Eval('component')),
                ('fraction.sample.state', '!=', 'annulled')],
               [('fraction.sample.state', '!=', 'annulled')])
        ],
        depends=['free_precedents', 'component'])
    free_precedents = fields.Boolean('Free precedents')
    precedent1_diagnosis = fields.Function(
        fields.Text('Diagnosis Precedent 1'),
        'on_change_with_precedent1_diagnosis')
    precedent2_diagnosis = fields.Function(
        fields.Text('Diagnosis Precedent 2'),
        'on_change_with_precedent2_diagnosis')
    precedent3_diagnosis = fields.Function(
        fields.Text('Diagnosis Precedent 3'),
        'on_change_with_precedent3_diagnosis')
    precedent1_diagnosis_states = fields.Function(
        fields.Dict('lims.diagnosis.state', 'Diagnosis States Precedent 1'),
        'get_precedent_diagnosis')
    precedent2_diagnosis_states = fields.Function(
        fields.Dict('lims.diagnosis.state', 'Diagnosis States Precedent 2'),
        'get_precedent_diagnosis')
    precedent3_diagnosis_states = fields.Function(
        fields.Dict('lims.diagnosis.state', 'Diagnosis States Precedent 3'),
        'get_precedent_diagnosis')

    @staticmethod
    def default_free_precedents():
        return False

    @classmethod
    def view_attributes(cls):
        missing_diagnosis = True if 'diagnosis' not in cls._fields else False
        return super().view_attributes() + [
            ('//group[@id="diagnosis"]', 'states', {
                'invisible': missing_diagnosis,
            }),
        ]

    @fields.depends('precedent1')
    def on_change_with_precedent1_diagnosis(self, name=None):
        if self.precedent1:
            result = self.get_precedent_diagnosis((self, ),
                                                  ('precedent1_diagnosis', ))
            return result['precedent1_diagnosis'][self.id]
        return None

    @fields.depends('precedent2')
    def on_change_with_precedent2_diagnosis(self, name=None):
        if self.precedent2:
            result = self.get_precedent_diagnosis((self, ),
                                                  ('precedent2_diagnosis', ))
            return result['precedent2_diagnosis'][self.id]
        return None

    @fields.depends('precedent3')
    def on_change_with_precedent3_diagnosis(self, name=None):
        if self.precedent3:
            result = self.get_precedent_diagnosis((self, ),
                                                  ('precedent3_diagnosis', ))
            return result['precedent3_diagnosis'][self.id]
        return None

    @classmethod
    def get_precedent_diagnosis(cls, samples, names):
        result = {}
        missing_diagnosis = True if 'diagnosis' not in cls._fields else False
        if missing_diagnosis:
            for name in names:
                result[name] = {}
                for s in samples:
                    result[name][s.id] = None
        else:
            for name in names:
                result[name] = {}
                if 'precedent1' in name:
                    for s in samples:
                        result[name][s.id] = cls._get_precedent_diagnosis(
                            s.precedent1, name)
                elif 'precedent2' in name:
                    for s in samples:
                        result[name][s.id] = cls._get_precedent_diagnosis(
                            s.precedent2, name)
                else:  # name == 'precedent3_diagnosis':
                    for s in samples:
                        result[name][s.id] = cls._get_precedent_diagnosis(
                            s.precedent3, name)
        return result

    @classmethod
    def _get_precedent_diagnosis(cls, precedent, name):
        if not precedent:
            return None
        precedent_sample = cls.search([
            ('notebook', '=', precedent),
        ])
        if not precedent_sample:
            return None
        return (precedent_sample[0].diagnosis_states
                if 'states' in name else precedent_sample[0].diagnosis)

    @classmethod
    def _get_fields_from_sample(cls, sample, only_accepted=True):
        sample_default = super()._get_fields_from_sample(sample, only_accepted)
        sample_default['precedent1'] = (sample.precedent1 and sample.precedent1
                                        or None)
        sample_default['precedent2'] = (sample.precedent2 and sample.precedent2
                                        or None)
        sample_default['precedent3'] = (sample.precedent3 and sample.precedent3
                                        or None)
        sample_default['precedent4'] = (sample.precedent4 and sample.precedent4
                                        or None)
        sample_default['precedent5'] = (sample.precedent5 and sample.precedent5
                                        or None)
        sample_default['precedent6'] = (sample.precedent6 and sample.precedent6
                                        or None)
        sample_default['precedent7'] = (sample.precedent7 and sample.precedent7
                                        or None)
        sample_default['precedent8'] = (sample.precedent8 and sample.precedent8
                                        or None)
        return sample_default

    @classmethod
    def create(cls, vlist):
        samples = super().create(vlist)
        for sample in samples:
            if not sample.precedent1:
                precedents = cls.get_default_precedents(sample)
                if not precedents:
                    continue
                for i in range(0, min(3, len(precedents))):
                    setattr(sample, 'precedent%s' % str(i + 1), precedents[i])
                sample.save()
                cls.update_precedent_lines(sample)
        return samples

    @classmethod
    def write(cls, *args):
        super().write(*args)
        update_precedent_lines = False
        if not update_precedent_lines:
            return
        actions = iter(args)
        for samples, vals in zip(actions, actions):
            change_precedents = False
            for field in [
                    'precedent1', 'precedent2', 'precedent3', 'precedent4',
                    'precedent5', 'precedent6', 'precedent7', 'precedent8'
            ]:
                if field in vals:
                    change_precedents = True
            if change_precedents:
                for sample in samples:
                    cls.update_precedent_lines(sample)

    @staticmethod
    def get_default_precedents(sample):
        pool = Pool()
        Notebook = pool.get('lims.notebook')
        if not sample.component:
            return []
        precedents = Notebook.search([
            ('id', '!=', sample.notebook.id),
            ('component', '=', sample.component),
            ('fraction.sample.state', '!=', 'annulled'),
            ('invoice_party', '=', sample.notebook.invoice_party),
        ],
                                     order=[
                                         ('fraction.sample.number', 'DESC'),
                                     ],
                                     limit=3)
        return precedents

    @classmethod
    def update_precedent_lines(cls, sample):
        pool = Pool()
        ResultsLine = pool.get('lims.results_report.version.detail.line')
        NotebookLine = pool.get('lims.notebook.line')

        precedent_lines = ResultsLine.search([
            ('detail_sample', '=', sample.id),
            ('notebook_line', '=', None),
        ])
        if precedent_lines:
            ResultsLine.delete(precedent_lines)

        result_lines = ResultsLine.search([
            ('detail_sample', '=', sample.id),
        ])
        analysis = [rl.notebook_line.analysis.id for rl in result_lines]

        lines_to_create = []
        for precedent in [
                sample.precedent1, sample.precedent2, sample.precedent3
        ]:
            if not precedent:
                continue
            precedent_lines = NotebookLine.search([
                ('notebook', '=', precedent),
                ('analysis', 'not in', analysis),
                ('accepted', '=', True),
            ])
            for line in precedent_lines:
                lines_to_create.append({
                    'detail_sample': sample.id,
                    'precedent_analysis': line.analysis.id,
                })
                analysis.append(line.analysis.id)

        if lines_to_create:
            ResultsLine.create(lines_to_create)
Example #22
0
class DictSchemaMixin(object):
    _rec_name = 'string'
    name = fields.Char('Name', required=True)
    string = fields.Char('String', translate=True, required=True)
    type_ = fields.Selection([
        ('boolean', 'Boolean'),
        ('integer', 'Integer'),
        ('char', 'Char'),
        ('float', 'Float'),
        ('numeric', 'Numeric'),
        ('date', 'Date'),
        ('datetime', 'DateTime'),
        ('selection', 'Selection'),
    ],
                             'Type',
                             required=True)
    digits = fields.Integer('Digits',
                            states={
                                'invisible':
                                ~Eval('type_').in_(['float', 'numeric']),
                            },
                            depends=['type_'])
    selection = fields.Text(
        'Selection',
        states={
            'invisible': Eval('type_') != 'selection',
        },
        translate=True,
        depends=['type_'],
        help='A couple of key and label separated by ":" per line')
    selection_sorted = fields.Boolean(
        'Selection Sorted',
        states={
            'invisible': Eval('type_') != 'selection',
        },
        depends=['type_'],
        help='If the selection must be sorted on label')
    selection_json = fields.Function(
        fields.Char('Selection JSON',
                    states={
                        'invisible': Eval('type_') != 'selection',
                    },
                    depends=['type_']), 'get_selection_json')

    @classmethod
    def __setup__(cls):
        super(DictSchemaMixin, cls).__setup__()
        cls.__rpc__.update({
            'get_keys': RPC(instantiate=0),
        })

    @staticmethod
    def default_digits():
        return 2

    @staticmethod
    def default_selection_sorted():
        return True

    def get_selection_json(self, name):
        db_selection = self.selection or ''
        selection = [[w.strip() for w in v.split(':', 1)]
                     for v in db_selection.splitlines() if v]
        return json.dumps(selection, separators=(',', ':'))

    @classmethod
    def get_keys(cls, records):
        pool = Pool()
        Config = pool.get('ir.configuration')
        keys = []
        for record in records:
            new_key = {
                'id': record.id,
                'name': record.name,
                'string': record.string,
                'type_': record.type_,
            }
            if record.type_ == 'selection':
                with Transaction().set_context(language=Config.get_language()):
                    english_key = cls(record.id)
                    selection = OrderedDict(
                        json.loads(english_key.selection_json))
                selection.update(dict(json.loads(record.selection_json)))
                new_key['selection'] = selection.items()
                new_key['sorted'] = record.selection_sorted
            elif record.type_ in ('float', 'numeric'):
                new_key['digits'] = (16, record.digits)
            keys.append(new_key)
        return keys
Example #23
0
class Location(DeactivableMixin, tree(), ModelSQL, ModelView):
    "Stock Location"
    __name__ = 'stock.location'
    _default_warehouse_cache = Cache('stock.location.default_warehouse',
        context=False)

    name = fields.Char("Name", size=None, required=True, translate=True)
    code = fields.Char(
        "Code", size=None, select=True,
        help="The internal identifier used for the location.")
    address = fields.Many2One(
        'party.address', "Address",
        states={
            'invisible': Eval('type') != 'warehouse',
            },
        depends=['type'])
    type = fields.Selection([
        ('supplier', 'Supplier'),
        ('customer', 'Customer'),
        ('lost_found', 'Lost and Found'),
        ('warehouse', 'Warehouse'),
        ('storage', 'Storage'),
        ('production', 'Production'),
        ('drop', 'Drop'),
        ('view', 'View'),
        ], "Location type")
    type_string = type.translated('type')
    parent = fields.Many2One("stock.location", "Parent", select=True,
        left="left", right="right",
        states={
            'invisible': Eval('type') == 'warehouse',
            },
        depends=['type'],
        help="Used to add structure above the location.")
    left = fields.Integer('Left', required=True, select=True)
    right = fields.Integer('Right', required=True, select=True)
    childs = fields.One2Many("stock.location", "parent", "Children",
        help="Used to add structure below the location.")
    flat_childs = fields.Boolean(
        "Flat Children",
        help="Check to enforce a single level of children with no "
        "grandchildren.")
    warehouse = fields.Function(fields.Many2One('stock.location', 'Warehouse'),
        'get_warehouse')
    input_location = fields.Many2One(
        "stock.location", "Input", states={
            'invisible': Eval('type') != 'warehouse',
            'required': Eval('type') == 'warehouse',
            },
        domain=[
            ('type', '=', 'storage'),
            ['OR',
                ('parent', 'child_of', [Eval('id')]),
                ('parent', '=', None),
                ],
            ],
        depends=['type', 'id'],
        help="Where incoming stock is received.")
    output_location = fields.Many2One(
        "stock.location", "Output", states={
            'invisible': Eval('type') != 'warehouse',
            'required': Eval('type') == 'warehouse',
        },
        domain=[
            ('type', '=', 'storage'),
            ['OR',
                ('parent', 'child_of', [Eval('id')]),
                ('parent', '=', None)]],
        depends=['type', 'id'],
        help="Where outgoing stock is sent from.")
    storage_location = fields.Many2One(
        "stock.location", "Storage", states={
            'invisible': Eval('type') != 'warehouse',
            'required': Eval('type') == 'warehouse',
        },
        domain=[
            ('type', 'in', ['storage', 'view']),
            ['OR',
                ('parent', 'child_of', [Eval('id')]),
                ('parent', '=', None)]],
        depends=['type', 'id'],
        help="The top level location where stock is stored.")
    picking_location = fields.Many2One(
        'stock.location', 'Picking', states={
            'invisible': Eval('type') != 'warehouse',
            },
        domain=[
            ('type', '=', 'storage'),
            ('parent', 'child_of', [Eval('storage_location', -1)]),
            ],
        depends=['type', 'storage_location'],
        help="Where stock is picked from.\n"
        "Leave empty to use the storage location.")
    lost_found_location = fields.Many2One(
        'stock.location', "Lost and Found",
        states={
            'invisible': Eval('type') != 'warehouse',
            'readonly': ~Eval('active'),
            },
        domain=[
            ('type', '=', 'lost_found'),
            ],
        depends=['type', 'active'],
        help="Used, by inventories, when correcting stock levels "
        "in the warehouse.")
    waste_locations = fields.Many2Many(
        'stock.location.waste', 'warehouse', 'location', "Waste Locations",
        states={
            'invisible': Eval('type') != 'warehouse',
            },
        domain=[
            ('type', '=', 'lost_found'),
            ],
        depends=['type'],
        help="The locations used for waste products from the warehouse.")
    waste_warehouses = fields.Many2Many(
        'stock.location.waste', 'location', 'warehouse', "Waste Warehouses",
        states={
            'invisible': Eval('type') != 'lost_found',
            },
        domain=[
            ('type', '=', 'warehouse'),
            ],
        depends=['type'],
        help="The warehouses that use the location for waste products.")
    quantity = fields.Function(
        fields.Float('Quantity',
        help="The amount of stock in the location."),
        'get_quantity', searcher='search_quantity')
    forecast_quantity = fields.Function(
        fields.Float('Forecast Quantity',
        help="The amount of stock expected to be in the location."),
        'get_quantity', searcher='search_quantity')
    cost_value = fields.Function(fields.Numeric('Cost Value',
        help="The value of the stock in the location."),
        'get_cost_value')

    @classmethod
    def __setup__(cls):
        super(Location, cls).__setup__()
        cls._order.insert(0, ('name', 'ASC'))

        parent_domain = [
            ['OR',
                ('parent.flat_childs', '=', False),
                ('parent', '=', None),
                ]
            ]
        childs_domain = [
            If(Eval('flat_childs', False),
                ('childs', '=', None),
                ()),
            ]
        childs_mapping = cls._childs_domain()
        for type_, allowed_parents in cls._parent_domain().items():
            parent_domain.append(If(Eval('type') == type_,
                    ('type', 'in', allowed_parents), ()))
            childs_domain.append(If(Eval('type') == type_,
                    ('type', 'in', childs_mapping[type_]), ()))
        cls.parent.domain = parent_domain
        cls.childs.domain = childs_domain
        cls.childs.depends.extend(['flat_childs', 'type'])

    @classmethod
    def _parent_domain(cls):
        '''Returns a dict with location types as keys and a list of allowed
        parent location types as values'''
        return {
            'customer': ['customer'],
            'supplier': ['supplier'],
            'production': ['production'],
            'lost_found': ['lost_found'],
            'view': ['warehouse', 'view', 'storage'],
            'storage': ['warehouse', 'view', 'storage'],
            'warehouse': [''],
            }

    @classmethod
    def _childs_domain(cls):
        childs_domain = {}
        for type_, allowed_parents in cls._parent_domain().items():
            for parent in allowed_parents:
                childs_domain.setdefault(parent, [])
                childs_domain[parent].append(type_)
        return childs_domain

    @classmethod
    def __register__(cls, module_name):
        super(Location, cls).__register__(module_name)

        table = cls.__table_handler__(module_name)
        table.index_action(['left', 'right'], 'add')

    @classmethod
    def validate(cls, locations):
        super(Location, cls).validate(locations)
        inactives = []
        for location in locations:
            location.check_type_for_moves()
            if not location.active:
                inactives.append(location)
        cls.check_inactive(inactives)

    def check_type_for_moves(self):
        """ Check locations with moves have types compatible with moves. """
        invalid_move_types = ['warehouse', 'view']
        Move = Pool().get('stock.move')
        if self.type in invalid_move_types:
            # Use root to compute for all companies
            with Transaction().set_user(0):
                moves = Move.search([
                        ['OR',
                            ('to_location', '=', self.id),
                            ('from_location', '=', self.id),
                            ],
                        ('state', 'not in', ['staging', 'draft']),
                        ])
            if moves:
                raise LocationValidationError(
                    gettext('stock.msg_location_invalid_type_for_moves',
                        location=self.rec_name,
                        type=self.type_string))

    @classmethod
    def check_inactive(cls, locations):
        "Check inactive location are empty"
        assert all(not l.active for l in locations)
        empty = cls.get_empty_locations(locations)
        non_empty = set(locations) - set(empty)
        if non_empty:
            raise LocationValidationError(
                gettext('stock.msg_location_inactive_not_empty',
                    location=next(iter(non_empty)).rec_name))

    @classmethod
    def get_empty_locations(cls, locations=None):
        pool = Pool()
        Move = pool.get('stock.move')
        if locations is None:
            locations = cls.search([])
        if not locations:
            return []
        location_ids = list(map(int, locations))
        # Use root to compute for all companies
        # and ensures inactive locations are in the query
        with Transaction().set_user(0), \
                Transaction().set_context(active_test=False):
            query = Move.compute_quantities_query(
                location_ids, with_childs=True)
            quantities = Move.compute_quantities(
                query, location_ids, with_childs=True)
            empty = set(location_ids)
            for (location_id, product), quantity in quantities.items():
                if quantity:
                    empty.discard(location_id)
            for sub_ids in grouped_slice(list(empty)):
                sub_ids = list(sub_ids)
                moves = Move.search([
                        ('state', 'not in', ['done', 'cancelled']),
                        ['OR',
                            ('from_location', 'in', sub_ids),
                            ('to_location', 'in', sub_ids),
                            ],
                        ])
                for move in moves:
                    for location in [move.from_location, move.to_location]:
                        empty.discard(location.id)
        return cls.browse(empty)

    @staticmethod
    def default_left():
        return 0

    @staticmethod
    def default_right():
        return 0

    @classmethod
    def default_flat_childs(cls):
        return False

    @staticmethod
    def default_type():
        return 'storage'

    @classmethod
    def check_xml_record(cls, records, values):
        return True

    def get_warehouse(self, name):
        # Order by descending left to get the first one in the tree
        with Transaction().set_context(active_test=False):
            locations = self.search([
                    ('parent', 'parent_of', [self.id]),
                    ('type', '=', 'warehouse'),
                    ], order=[('left', 'DESC')])
        if locations:
            return locations[0].id

    @classmethod
    def get_default_warehouse(cls):
        warehouse = Transaction().context.get('warehouse')
        if warehouse:
            return warehouse

        warehouse = cls._default_warehouse_cache.get(None, -1)
        if warehouse == -1:
            warehouses = cls.search([
                    ('type', '=', 'warehouse'),
                    ], limit=2)
            if len(warehouses) == 1:
                warehouse = warehouses[0].id
            else:
                warehouse = None
            cls._default_warehouse_cache.set(None, warehouse)
        return warehouse

    @property
    def lost_found_used(self):
        if self.warehouse:
            return self.warehouse.lost_found_location

    @classmethod
    def search_rec_name(cls, name, clause):
        if clause[1].startswith('!') or clause[1].startswith('not '):
            bool_op = 'AND'
        else:
            bool_op = 'OR'
        return [bool_op,
            (cls._rec_name,) + tuple(clause[1:]),
            ('code',) + tuple(clause[1:]),
            ]

    @classmethod
    def _get_quantity_grouping(cls):
        context = Transaction().context
        grouping, grouping_filter, key = (), (), []
        if context.get('product') is not None:
            grouping = ('product',)
            grouping_filter = ([context['product']],)
            key = (context['product'],)
        elif context.get('product_template') is not None:
            grouping = ('product.template',)
            grouping_filter = ([context['product_template']],)
            key = (context['product_template'],)
        return grouping, grouping_filter, key

    @classmethod
    def get_quantity(cls, locations, name):
        pool = Pool()
        Product = pool.get('product.product')
        Date_ = pool.get('ir.date')
        trans_context = Transaction().context

        def valid_context(name):
            return (trans_context.get(name) is not None
                and isinstance(trans_context[name], int))

        context = {}
        if (name == 'quantity'
                and (trans_context.get('stock_date_end', datetime.date.max)
                    > Date_.today())):
            context['stock_date_end'] = Date_.today()

        if name == 'forecast_quantity':
            context['forecast'] = True
            if not trans_context.get('stock_date_end'):
                context['stock_date_end'] = datetime.date.max

        grouping, grouping_filter, key = cls._get_quantity_grouping()
        if not grouping:
            return {loc.id: None for loc in locations}

        pbl = {}
        for sub_locations in grouped_slice(locations):
            location_ids = [l.id for l in sub_locations]
            with Transaction().set_context(context):
                pbl.update(Product.products_by_location(
                        location_ids,
                        grouping=grouping,
                        grouping_filter=grouping_filter,
                        with_childs=trans_context.get('with_childs', True)))

        return dict((loc.id, pbl.get((loc.id,) + key, 0)) for loc in locations)

    @classmethod
    def search_quantity(cls, name, domain):
        _, operator_, operand = domain
        operator_ = {
            '=': operator.eq,
            '>=': operator.ge,
            '>': operator.gt,
            '<=': operator.le,
            '<': operator.lt,
            '!=': operator.ne,
            'in': lambda v, l: v in l,
            'not in': lambda v, l: v not in l,
            }.get(operator_, lambda v, l: False)

        ids = []
        for location in cls.search([]):
            if operator_(getattr(location, name), operand):
                ids.append(location.id)
        return [('id', 'in', ids)]

    @classmethod
    def get_cost_value(cls, locations, name):
        pool = Pool()
        Product = pool.get('product.product')
        Template = pool.get('product.template')
        trans_context = Transaction().context
        cost_values = {l.id: None for l in locations}

        def valid_context(name):
            return (trans_context.get(name) is not None
                and isinstance(trans_context[name], int))

        if not any(map(valid_context, ['product', 'product_template'])):
            return cost_values

        def get_record():
            if trans_context.get('product') is not None:
                return Product(trans_context['product'])
            else:
                return Template(trans_context['product_template'])

        context = {}
        if 'stock_date_end' in trans_context:
            # Use the last cost_price of the day
            context['_datetime'] = datetime.datetime.combine(
                trans_context['stock_date_end'], datetime.time.max)
            # The date could be before the product creation
            record = get_record()
            if record.create_date > context['_datetime']:
                return cost_values
        with Transaction().set_context(context):
            cost_price = get_record().cost_price
        # The template may have more than one product
        if cost_price is not None:
            for location in locations:
                cost_values[location.id] = (
                    Decimal(str(location.quantity)) * cost_price)
        return cost_values

    @classmethod
    def _set_warehouse_parent(cls, locations):
        '''
        Set the parent of child location of warehouse if not set
        '''
        to_update = set()
        to_save = []
        for location in locations:
            if location.type == 'warehouse':
                if not location.input_location.parent:
                    to_update.add(location.input_location)
                if not location.output_location.parent:
                    to_update.add(location.output_location)
                if not location.storage_location.parent:
                    to_update.add(location.storage_location)
                if to_update:
                    for child_location in to_update:
                        child_location.parent = location
                        to_save.append(child_location)
                    to_update.clear()
        cls.save(to_save)

    @classmethod
    def create(cls, vlist):
        locations = super(Location, cls).create(vlist)
        cls._set_warehouse_parent(locations)
        cls._default_warehouse_cache.clear()
        return locations

    @classmethod
    def write(cls, *args):
        super(Location, cls).write(*args)
        locations = sum(args[::2], [])
        cls._set_warehouse_parent(locations)
        cls._default_warehouse_cache.clear()

        ids = [l.id for l in locations]
        warehouses = cls.search([
                ('type', '=', 'warehouse'),
                ['OR',
                    ('storage_location', 'in', ids),
                    ('input_location', 'in', ids),
                    ('output_location', 'in', ids),
                    ]])

        fields = ('storage_location', 'input_location', 'output_location')
        wh2childs = {}
        for warehouse in warehouses:
            in_out_sto = (getattr(warehouse, f).id for f in fields)
            for location in locations:
                if location.id not in in_out_sto:
                    continue
                childs = wh2childs.setdefault(warehouse.id, cls.search([
                            ('parent', 'child_of', warehouse.id),
                            ]))
                if location not in childs:
                    raise LocationValidationError(
                        gettext('stock.msg_location_child_of_warehouse',
                            location=location.rec_name,
                            warehouse=warehouse.rec_name))

    @classmethod
    def delete(cls, *args):
        super().delete(*args)
        cls._default_warehouse_cache.clear()

    @classmethod
    def copy(cls, locations, default=None):
        if default is None:
            default = {}
        else:
            default = default.copy()

        res = []
        for location in locations:
            if location.type == 'warehouse':

                wh_default = default.copy()
                wh_default['type'] = 'view'
                wh_default['input_location'] = None
                wh_default['output_location'] = None
                wh_default['storage_location'] = None
                wh_default['childs'] = None

                new_location, = super(Location, cls).copy([location],
                    default=wh_default)

                with Transaction().set_context(
                        cp_warehouse_locations={
                            'input_location': location.input_location.id,
                            'output_location': location.output_location.id,
                            'storage_location': location.storage_location.id,
                            },
                        cp_warehouse_id=new_location.id):
                    cls.copy(location.childs,
                        default={'parent': new_location.id})
                cls.write([new_location], {
                        'type': 'warehouse',
                        })
            else:
                new_location, = super(Location, cls).copy([location],
                    default=default)
                warehouse_locations = Transaction().context.get(
                    'cp_warehouse_locations') or {}
                if location.id in warehouse_locations.values():
                    cp_warehouse = cls(
                        Transaction().context['cp_warehouse_id'])
                    for field, loc_id in warehouse_locations.items():
                        if loc_id == location.id:
                            cls.write([cp_warehouse], {
                                    field: new_location.id,
                                    })

            res.append(new_location)
        return res

    @classmethod
    def view_attributes(cls):
        storage_types = Eval('type').in_(['storage', 'warehouse', 'view'])
        return super().view_attributes() + [
            ('/tree/field[@name="quantity"]',
                'visual', If(
                    storage_types & (Eval('quantity', 0) < 0), 'danger', ''),
                ['type']),
            ('/tree/field[@name="forecast_quantity"]',
                'visual', If(
                    storage_types & (Eval('forecast_quantity', 0) < 0),
                    'warning', ''),
                ['type']),
            ]
class Asset():
    __metaclass__ = PoolMeta
    __name__ = 'account.asset'

    rate = fields.Numeric(
        'Rate',
        digits=(14, 10),
        states={
            'readonly': (Eval('lines', [0]) | (Eval('state') != 'draft')),
            'invisible': (Eval('depreciation_method') != 'declining_balance'),
            'required': (Eval('depreciation_method') == 'declining_balance'),
        },
        depends=['state', 'depreciation_method'])
    half_year_rule = fields.Boolean(
        'Half Year Rule',
        states={
            'readonly': (Eval('lines', [0]) | (Eval('state') != 'draft')),
            'invisible': (Eval('depreciation_method') != 'declining_balance'),
        },
        depends=['state', 'depreciation_method'])

    @classmethod
    def __setup__(cls):
        super(Asset, cls).__setup__()
        cls.depreciation_method.selection.append(
            ('declining_balance', 'Declining Balance'))

    def compute_depreciation(self, date, dates):
        """
        Returns the depreciation amount for an asset on a certain date.
        """
        # calculate remaining amount to depreciate.
        amount = (self.value - self.get_depreciated_amount() -
                  self.residual_value)
        if self.depreciation_method == 'linear':
            super(Asset, cls).compute_depreciation(self, date, dates)
        elif self.depreciation_method == 'declining_balance':
            # V = P * (1 - R) ** N
            #     V is the depreciated value after N periods
            #     P is value to depreciate
            #     R is rate of depreciation at each period
            start_date = max(
                [self.start_date - relativedelta.relativedelta(days=1)] +
                [l.date for l in self.lines])
            # Calculate number of periods in depreciation range.
            delta = relativedelta.relativedelta(date, start_date)
            if self.frequency == 'monthly':
                period = delta.months + 12 * delta.years
                if delta.days > 0:
                    period += 1
            elif self.frequency == 'yearly':
                period = delta.years
                if delta.months > 0:
                    period += 1
            if self.get_depreciated_amount() > 0:
                # Asset has some depreciation posted.
                # Half Year Rule irrelevant here.
                #
                print "Depreciating unposted remainder."
            else:
                # Asset has not posted depreciation yet.
                balance = self.value
                for n in range(0, period):
                    depreciation = (balance - self.residual_value) * self.rate
                    if n == 0 and self.half_year_rule:
                        depreciation *= Decimal(0.5)
                    balance -= depreciation
            return self.company.currency.round(depreciation)
Example #25
0
class New_products(ModelSQL, ModelView):
    "New_product"
    __name__ = "hrp_product.new_products"
    _order_name = 'rec_name'
    manufacturers_code = fields.Function(fields.Char('Manufacturers_code'),
                                         'get_manufacturers_code',
                                         'set_manufacturers_code')
    medical_insurance_code = fields.Function(
        fields.Char('Medical_insurance_code', select=True),
        'get_medical_insurance_code', 'set_medical_insurance_code')
    attach = fields.Function(fields.Char('Attach', select=True), 'get_attach',
                             'set_attach')
    concentration = fields.Function(fields.Char('Concentration', select=True),
                                    'get_concentration', 'set_concentration')
    concentration_unit = fields.Function(
        fields.Char('Concentration_unit', select=True),
        'get_concentration_unit', 'set_concentration_unit')
    dose = fields.Function(fields.Char('Dose', select=True), 'get_dose',
                           'set_dose')
    dose_unit = fields.Function(fields.Char('Dose_unit', select=True),
                                'get_dose_unit', 'set_dose_unit')
    retrieve_the_code = fields.Function(
        fields.Char('Retrieve_the_code', select=True,
                    required=True), 'get_retrieve_the_code',
        'set_retrieve_the_code', 'search_retrieve_the_code')
    capacity = fields.Function(fields.Char('Capacity', select=True),
                               'get_capacity', 'set_capacity')
    drug_specifications = fields.Function(
        fields.Char('Drug_specifications', select=True, readonly=True),
        'get_drug_specifications', 'set_drug_specifications')
    is_direct_sending = fields.Function(
        fields.Boolean('Is_direct_sending', select=True),
        'get_is_direct_sending', 'set_is_direct_sending')
    is_antimicrobials = fields.Function(
        fields.Boolean('Is_antimicrobials', select=True),
        'get_is_antimicrobials', 'set_is_antimicrobials')
    a_charge = fields.Function(
        fields.Integer('A_charge', select=True, readonly=False),
        'get_a_charge', 'set_a_charge')
    drup_level = fields.Function(fields.Char('Drup_level', select=True),
                                 'get_drup_level', 'set_drup_level')
    compound_dose = fields.Function(fields.Float('Compound_dose', select=True),
                                    'get_compound_dose', 'set_compound_dose')
    purchase_code = fields.Function(
        fields.Char('purchase_code', select=True, required=True),
        'get_purchase_code', 'set_purchase_code')
    retail_package = fields.Function(
        fields.Many2One('product.uom', 'Retail Package'), 'get_retail_package',
        'set_retail_package')
    medical_insurance_description = fields.Function(
        fields.Char('Medical_insurance_description',
                    select=True), 'get_medical_insurance_description',
        'set_medical_insurance_description')
    new_term = fields.Function(fields.Char('new_term', select=True),
                               'get_new_term', 'set_new_term')
    state = fields.Function(fields.Char('State', select=True, required=False),
                            'get_state', 'set_state')
    min_Package = fields.Function(
        fields.Many2One('product.uom', 'Min_Package', required=False),
        'get_min_Package', 'set_min_Package')
    uom_min_Package = fields.Function(
        fields.Char('Uom Min Package', required=True), 'get_uom_min_Package',
        'set_uom_min_Package')
    dosage_form_description = fields.Function(
        fields.Char('Dosage_form_description', select=True),
        'get_dosage_form_description', 'set_dosage_form_description')
    manufacturers_describtion = fields.Function(
        fields.Char('Manufacturers_describtion', required=False, select=True),
        'get_manufacturers_describtion', 'set_manufacturers_describtion')
    poison_hemp_spirit = fields.Function(
        fields.Selection([('common', u'普通'), ('narcosis', u'麻醉'),
                          ('spirit_one', u'精神1'), ('spirit_two', u'精神2')],
                         'Poison_hemp_spirit',
                         select=True), 'get_poison_hemp_spirit',
        'set_poison_hemp_spirit')
    national_essential_medicines = fields.Function(
        fields.Boolean('National_essential_medicines', select=True),
        'get_national_essential_medicines', 'set_national_essential_medicines')
    interim = fields.Function(
        fields.Selection([('1', u''), ('2', u'是')], 'interim', select=True),
        'get_interim', 'set_interim')
    #############################
    mark = fields.Many2One('product.template', 'Mark', select=True)
    name = fields.Function(
        fields.Char("Name",
                    size=None,
                    required=True,
                    translate=True,
                    select=True,
                    states=STATES,
                    depends=DEPENDS), "get_name", "set_name", "searcher_name")
    active = fields.Function(
        fields.Boolean('Active', select=False, readonly=True), "get_active",
        "set_active", 'seacher_active')
    type = fields.Function(
        fields.Selection(TYPES,
                         'Type',
                         required=True,
                         states=STATES,
                         depends=DEPENDS), "get_type", "set_type")
    default_uom = fields.Function(
        fields.Many2One('product.uom',
                        'Default UOM',
                        required=False,
                        states=STATES,
                        depends=DEPENDS), 'get_default_uom', 'set_default_uom')
    uom_default_uom = fields.Function(
        fields.Char('Uom Default UOM',
                    required=True,
                    states=STATES,
                    depends=DEPENDS), 'get_uom_default_uom',
        'set_uom_default_uom')
    code = fields.Function(
        fields.Char("Code",
                    size=None,
                    required=True,
                    states=STATES,
                    depends=DEPENDS), 'get_code', 'set_code')
    list_price = fields.Function(
        fields.Property(
            fields.Numeric(
                'List Price',
                states={
                    'readonly': False
                    # Eval('drug_specifications') != '',
                },
                digits=price_digits,
                depends=['active', 'default_uom'],
                required=True)),
        'get_list_price',
        'set_list_price')
    cost_price = fields.Function(
        fields.Property(
            fields.Numeric(
                'Cost Price',
                states={
                    'readonly': False  # Eval('drug_specifications') != '',
                },
                digits=price_digits,
                depends=DEPENDS,
                required=True)),
        'get_list_price',
        'set_cost_price')
    cost_price_method = fields.Function(
        fields.Property(
            fields.Selection(COST_PRICE_METHODS,
                             'Cost Method',
                             required=True,
                             states=STATES,
                             depends=DEPENDS)), 'get_cost_price_method',
        'set_cost_price_method')
    categories = fields.Function(
        fields.Many2One('product.category',
                        'Categories',
                        required=True,
                        states=STATES,
                        depends=DEPENDS), 'get_categories', 'set_categories',
        'search_categories')
    salable = fields.Function(
        fields.Boolean('Salable',
                       states={
                           'readonly': ~Eval('active', True),
                       },
                       depends=['active']), 'get_salable', 'set_salable')
    purchasable = fields.Function(
        fields.Boolean('Purchasable',
                       states={
                           'readonly': ~Eval('active', True),
                       },
                       depends=['active']), 'get_purchasable',
        'set_purchasable')

    consumable = fields.Function(
        fields.Boolean('Consumable',
                       states={
                           'readonly': True,
                           'invisible': Eval('type', 'goods') != 'goods',
                       },
                       depends=['active', 'type']), 'get_consumable',
        'set_consumable')
    party = fields.Function(
        fields.Many2One('party.party',
                        'Supplier',
                        domain=[('type_', '=', 'supplier')],
                        required=True,
                        ondelete='CASCADE',
                        select=True), 'get_party', 'set_party')
    approval_number = fields.Function(fields.Char('Approval number'),
                                      'get_approa_number',
                                      'set_approval_number')
    is_atict = fields.Function(fields.Boolean('is_atict'), 'get_is_atict',
                               'set_is_atict')
    homemade = fields.Function(fields.Boolean('homemade'), 'get_homemade',
                               'set_homemade')

    @classmethod
    def searcher_name(cls, name, clause):
        New_products = Pool().get("hrp_product.new_products")
        product = New_products.search([])
        ids = []
        for i in product:
            if clause[2].strip('%') in i.name:
                ids.append(i.id)
        return [('id', 'in', ids)]

    @classmethod
    def search_categories(cls, name, clause):
        New_products = Pool().get("hrp_product.new_products")
        product = New_products.search([])
        ids = []
        for i in product:
            if clause[2].strip('%') == i.categories.name:
                ids.append(i.id)
        return [('id', 'in', ids)]

    @classmethod
    def search_retrieve_the_code(cls, name, clause):
        pass

    def get_homemade(self, name):
        return self.mark.homemade

    @classmethod
    def set_homemade(cls, homemade, name, value):
        pass

    def get_is_atict(self, name):
        return self.mark.is_atict

    @classmethod
    def set_is_atict(cls, set_is_atict, name, value):
        pass

    def get_approa_number(self, name):
        return self.mark.approval_number

    @classmethod
    def set_approval_number(cls, set_approval_number, name, value):
        pass

    def get_manufacturers_code(self, name):
        return self.mark.manufacturers_code

    def get_party(self, name):
        party = self.mark.product_suppliers
        if party:
            party = party[0].party.id
            return party

    def get_national_essential_medicines(self, name):
        return self.mark.national_essential_medicines

    def get_interim(self, name):
        return self.mark.interim

    def get_poison_hemp_spirit(self, name):
        return self.mark.poison_hemp_spirit

    def get_manufacturers_describtion(self, name):
        return self.mark.manufacturers_describtion

    def get_dosage_form_description(self, name):
        return self.mark.dosage_form_description

    def get_uom_min_Package(self, name):
        return self.mark.min_Package.name

    def get_min_Package(self, name):
        return self.mark.min_Package.id

    def get_state(self, name):
        return self.mark.state

    def get_medical_insurance_description(self, name):
        return self.mark.medical_insurance_description

    def get_new_term(self, name):
        return self.mark.new_term

    def get_retail_package(self, name):
        return self.mark.retail_package.id

    def get_purchase_code(self, name):
        return self.mark.purchase_code

    def get_compound_dose(self, name):
        return self.mark.compound_dose

    def get_drup_level(self, name):
        return self.mark.drup_level

    def get_a_charge(self, name):
        return self.mark.a_charge

    def get_is_direct_sending(self, name):
        return self.mark.is_direct_sending

    def get_is_antimicrobials(self, name):
        return self.mark.is_antimicrobials

    def get_drug_specifications(self, name):
        return self.mark.drug_specifications

    def get_capacity(self, name):
        return self.mark.capacity

    def get_retrieve_the_code(self, name):
        return self.mark.retrieve_the_code

    def get_dose_unit(self, name):
        return self.mark.dose_unit

    def get_dose(self, name):
        return self.mark.dose

    def get_concentration_unit(self, name):
        return self.mark.concentration_unit

    def get_concentration(self, name):
        return self.mark.concentration

    def get_attach(self, name):
        return self.mark.attach

    def get_medical_insurance_code(self, name):
        return self.mark.medical_insurance_code

    def get_name(self, name):
        return self.mark.name

    def get_active(self, name):
        return self.mark.active

    def get_type(self, name):
        return self.mark.type

    def get_uom_default_uom(self, name):
        return self.mark.default_uom.name

    def get_default_uom(self, name):  ###
        return self.mark.default_uom.id

    def get_code(self, name):
        return self.mark.products[0].code

    def get_list_price(self, name):
        list_price = self.mark.list_price
        list_prices = self.mark.cost_price
        if name == 'cost_price':
            return list_prices
        if name == 'list_price':
            return list_price

    def get_cost_price(self, name):
        return self.mark.cost_price

    def get_cost_price_method(self, name):
        return self.mark.cost_price_method

    def get_categories(self, name):
        categories = self.mark.categories
        if categories:
            ids = categories[0].id
            return ids

    def get_salable(self, name):
        return self.mark.salable

    def get_purchasable(self, name):
        return self.mark.purchasable

    def get_consumable(self, name):
        return self.mark.consumable

    @classmethod
    def set_name(cls, set_name, name, value):
        pass

    @classmethod
    def set_is_antimicrobials(cls, set_is_antimicrobials, name, value):
        pass

    @classmethod
    def set_party(cls, set_party, name, value):
        pass

    @classmethod
    def set_manufacturers_code(cls, set_manufacturers_code, name, value):
        pass

    @classmethod
    def set_medical_insurance_code(cls, set_medical_insurance_code, name,
                                   value):
        pass

    @classmethod
    def set_get_manufacturers_code(cls, get_manufacturers_code, name, value):
        pass

    @classmethod
    def set_attach(cls, set_attach, name, value):
        pass

    @classmethod
    def set_concentration(cls, set_concentration, name, value):
        pass

    @classmethod
    def set_concentration_unit(cls, set_concentration_unit, name, value):
        pass

    @classmethod
    def set_dose(cls, set_dose, name, value):
        pass

    @classmethod
    def set_dose_unit(cls, set_dose_unit, name, value):
        pass

    @classmethod
    def set_retrieve_the_code(cls, set_retrieve_the_code, name, value):
        pass

    @classmethod
    def set_capacity(cls, set_capacity, name, value):
        pass

    @classmethod
    def set_drug_specifications(cls, set_drug_specifications, name, value):
        pass

    @classmethod
    def set_is_direct_sending(cls, set_is_direct_sending, name, value):
        pass

    @classmethod
    def set_a_charge(cls, set_a_charge, name, value):
        pass

    @classmethod
    def set_drup_level(cls, set_drup_level, name, value):
        pass

    @classmethod
    def set_compound_dose(cls, set_compound_dose, name, value):
        pass

    @classmethod
    def set_purchase_code(cls, set_purchase_code, name, value):
        pass

    @classmethod
    def set_retail_package(cls, set_retail_package, name, value):
        pass

    @classmethod
    def set_medical_insurance_description(cls,
                                          set_medical_insurance_description,
                                          name, value):
        pass

    @classmethod
    def set_new_term(cls, set_new_term, name, value):
        pass

    @classmethod
    def set_state(cls, set_state, name, value):
        pass

    @classmethod
    def set_min_Package(cls, set_min_Package, name, value):
        pass

    @classmethod
    def set_uom_min_Package(cls, set_min_Package, name, value):
        pass

    @classmethod
    def set_dosage_form_description(cls, set_dosage_form_description, name,
                                    value):
        pass

    @classmethod
    def set_manufacturers_describtion(cls, set_manufacturers_describtion, name,
                                      value):
        pass

    @classmethod
    def set_poison_hemp_spirit(cls, set_poison_hemp_spirit, name, value):
        pass

    @classmethod
    def set_national_essential_medicines(cls, set_national_essential_medicines,
                                         name, value):
        pass

    @classmethod
    def set_interim(cls, set_interim, name, value):
        pass

    @classmethod
    def set_code(cls, set_code, name, value):
        pass

    @classmethod
    def set_active(cls, set_active, name, value):
        pass

    @classmethod
    def set_type(cls, set_type, name, value):
        pass

    @classmethod
    def set_default_uom(cls, set_default_uom, name, value):
        pass

    @classmethod
    def set_uom_default_uom(cls, set_default_uom, name, value):
        pass

    @classmethod
    def set_list_price(cls, set_list_price, name, value):
        pass

    @classmethod
    def set_cost_price(cls, set_cost_price, name, value):
        pass

    @classmethod
    def set_cost_price_method(cls, set_cost_price_method, name, value):
        pass

    @classmethod
    def set_categories(cls, set_categories, name, value):
        pass

    @classmethod
    def set_salable(cls, set_salable, name, value):
        pass

    @classmethod
    def set_purchasable(cls, set_purchasable, name, value):
        pass

    @classmethod
    def set_consumable(cls, set_consumable, name, value):
        pass

    @classmethod
    def seacher_active(cls, name, clause):
        pass

    @staticmethod
    def default_salable():
        return True

    @staticmethod
    def default_cost_price_method():
        return 'fixed'

    @staticmethod
    def default_purchasable():
        return True

    @staticmethod
    def default_approval_number():
        return ''

    @staticmethod
    def default_interim():
        return '00'

    @staticmethod
    def default_active():
        return True

    @staticmethod
    def default_consumable():
        return False

    @staticmethod
    def default_type():
        return 'goods'

    @fields.depends('code')
    def on_change_code(self, name=None):
        if self.code:
            for ch in self.code:
                if u'\u4e00' <= ch <= u'\u9fff':
                    raise TypeError("'Can't be Chinese")

    @classmethod
    def create(cls, vlist):
        pool = Pool()
        UomCategory = Pool().get('product.uom.category')
        Uom = Pool().get('product.uom')
        product_templates = pool.get("product.template")
        product_products = pool.get("product.product")
        product_supplier = pool.get("purchase.product_supplier")
        product_configurations = pool.get("product.configuration")
        product_configuration = product_configurations.search([])
        for value in vlist:
            product_codes = product_products.search([('name', '=',
                                                      value['code'])])
            if product_codes:
                cls.raise_user_error(u'%s已经存在!') % value['name']
            uom_category = UomCategory.create([{
                'name':
                value['name'] + '/' + value['code']
            }])
            uom_min_Package = Uom.create([{
                u'category': uom_category[0].id,
                u'digits': 2,
                u'name': value['uom_min_Package'],
                u'rounding': 1,
                u'symbol': value['uom_min_Package'],
                u'rate': 1.0,
                u'factor': 1.0,
                u'active': True
            }])
            uom_default_uom = Uom.create([{
                u'category':
                uom_category[0].id,
                u'digits':
                2,
                u'name':
                value['uom_default_uom'],
                u'rounding':
                0.01,
                u'symbol':
                value['uom_default_uom'],
                u'rate':
                round(1 / float(int(value['capacity'])), 12),
                u'factor':
                float(value['capacity']),
                u'active':
                True
            }])
            print value['name']
            is_antimicrobials = value['is_antimicrobials']
            party = value['party']
            medical_insurance_code = value['medical_insurance_code']
            attach = value['attach']
            concentration = value['concentration']
            concentration_unit = value['concentration_unit']
            dose_unit = value['dose_unit']
            retrieve_the_code = value['retrieve_the_code']
            capacity = value['capacity']
            is_direct_sending = value['is_direct_sending']
            approval_number = value['approval_number']
            a_charge = value['a_charge']
            drup_level = value['drup_level']
            compound_dose = value['compound_dose']
            purchase_code = value['purchase_code']
            retail_package = uom_min_Package[0].id  # value['retail_package']
            medical_insurance_description = value[
                'medical_insurance_description']
            new_term = value['new_term']
            state = value['state']
            min_Package = Uom(uom_min_Package[0].id)
            dosage_form_description = value['dosage_form_description']
            interim = value['interim']
            national_essential_medicines = value[
                'national_essential_medicines']
            poison_hemp_spirit = value['poison_hemp_spirit']
            manufacturers_describtion = value['manufacturers_describtion']
            name = value['name']
            active = True
            type = value['type']
            default_uom = uom_default_uom[0].id
            code = value['code']
            list_price = value['list_price']
            cost_price = value['cost_price']
            cost_price_method = value['cost_price_method']
            categories = [[u'add', [value['categories']]]]
            salable = value['salable']
            purchasable = value['purchasable']
            manufacturers_code = value['manufacturers_code']
            consumable = value['consumable']
            dose = value['dose']
            if 'dose' in value and dose != None:
                drug_specificationss = str(
                    value['dose'].encode('utf-8')) + str(
                        (value['dose_unit']).encode('utf-8')) + '*' + str(
                            (value['capacity']
                             ).encode('utf-8')) + str(min_Package)
            elif 'concentration' in value and concentration != None:
                drug_specificationss = str(
                    value['concentration']).encode('utf-8') + (
                        value['concentration_unit']
                    ).encode('utf-8') + '*' + str(
                        (value['capacity']).encode('utf-8')) + str(min_Package)
            else:
                drug_specificationss = '*' + str(
                    (value['capacity']).encode('utf-8')) + str(min_Package)
            value['drug_specifications'] = str(drug_specificationss)
            add_each = [{
                'is_antimicrobials': is_antimicrobials,
                'medical_insurance_code': medical_insurance_code,
                'attach': attach,
                'concentration': concentration,
                'concentration_unit': concentration_unit,
                'dose': dose,
                'dose_unit': dose_unit,
                'retrieve_the_code': retrieve_the_code,
                'capacity': capacity,
                'is_direct_sending': is_direct_sending,
                'a_charge': a_charge,
                'drup_level': drup_level,
                'compound_dose': compound_dose,
                'purchase_code': purchase_code,
                'retail_package': retail_package,
                'medical_insurance_description': medical_insurance_description,
                'new_term': new_term,
                'state': state,
                'manufacturers_code': manufacturers_code,
                'min_Package': min_Package,
                'dosage_form_description': dosage_form_description,
                'manufacturers_describtion': manufacturers_describtion,
                'poison_hemp_spirit': poison_hemp_spirit,
                'national_essential_medicines': national_essential_medicines,
                'interim': interim,
                'drug_specifications': drug_specificationss,
                'name': name,
                'active': active,
                'type': type,
                'default_uom': default_uom,
                'list_price': list_price,
                'cost_price': cost_price,
                'cost_price_method': cost_price_method,
                'categories': categories,
                'approval_number': approval_number,
                'salable': salable,
                'purchasable': purchasable,
                'consumable': consumable,
                'sale_uom': default_uom,
                'purchase_uom': default_uom,
            }]
            account_revenue = product_configuration[0].account_revenue
            shelf_life_state = product_configuration[0].shelf_life_state
            account_expense = product_configuration[0].account_expense
            expiration_state = product_configuration[0].expiration_state
            if account_revenue == None:
                raise ValueError('Please fill in the product configuration')
            else:
                add_each[0]['account_revenue'] = int(account_revenue)
            if shelf_life_state == None:
                raise ValueError('Please fill in the product configuration')
            else:
                add_each[0]['shelf_life_state'] = str(shelf_life_state)
            if account_expense == None:
                raise ValueError('Please fill in the product configuration')
            else:
                add_each[0]['account_expense'] = int(account_expense)
            if expiration_state == None:
                raise ValueError('Please fill in the product configuration')
            else:
                add_each[0]['expiration_state'] = str(expiration_state)

            product_template = product_templates.create(add_each)
            marks = int(product_template[0].id)
            product_product = product_products.create([{
                'template': marks,
                'code': code,
                'active': True
            }])
            product_supplier.create([{'product': marks, 'party': party}])
            value['mark'] = marks
        return super(New_products, cls).create(vlist)

    @classmethod
    def delete(cls, records):
        pool = Pool()
        UomCategory = Pool().get('product.uom.category')
        Uom = Pool().get('product.uom')
        product_templates = pool.get("product.template")
        product_products = pool.get("product.product")
        for value in records:
            mark = int(value.mark)
            product_template = product_templates.search([('id', '=', mark)])
            uom_uom_default_uom = Uom.search([
                ('category', '=', product_template[0].default_uom.category.id)
            ])
            uom_category = UomCategory.search([
                ('id', '=', product_template[0].default_uom.category.id)
            ])
            product_templates.delete(product_template)
            Uom.delete(uom_uom_default_uom)
            # UomCategory.delete(uom_category)
        return super(New_products, cls).delete(records)

    @classmethod
    def write(cls, records, values, *args):
        pool = Pool()
        UomCategory = Pool().get('product.uom.category')
        Uom = Pool().get('product.uom')
        product_templates = pool.get("product.template")
        product_products = pool.get("product.product")
        product_suppliers = pool.get("purchase.product_supplier")
        for ids in records:
            mark = int(ids.mark)
            product_template = product_templates.search([('id', '=', mark)])
            product_product = product_products.search([('template', '=', mark)
                                                       ])
            product_supplier = product_suppliers.search([('product', '=', mark)
                                                         ])
            uom_uom_min_Package = Uom.search([
                ('id', '=', product_template[0].min_Package.id)
            ])
            uom_uom_default_uom = Uom.search([
                ('id', '=', product_template[0].default_uom.id)
            ])
            uom_category = UomCategory.search([
                ('id', '=', product_template[0].default_uom.category.id)
            ])
            lv = {}
            lvc = {}
            uom_min_Package = {}
            uom_default_uom = {}
            if 'name' in values:
                UomCategory.write(uom_category, {
                    'name':
                    values['name'] + uom_category[0].name.split('/')[1]
                })
            if 'uom_min_Package' in values:
                uom_min_Package['name'] = values['uom_min_Package']
                uom_min_Package['symbol'] = values['uom_min_Package']
                values.pop('uom_min_Package')
                Uom.write(uom_uom_min_Package, uom_min_Package)
            if 'uom_default_uom' in values:
                uom_default_uom['name'] = values['uom_default_uom']
                uom_default_uom['symbol'] = values['uom_default_uom']
                values.pop('uom_default_uom')
            if 'capacity' in values:
                Uom.write(uom_uom_default_uom, {'active': False})
                uom_uom_default_uom = Uom.create([{
                    u'category':
                    uom_category[0].id,
                    u'digits':
                    2,
                    u'name':
                    uom_uom_default_uom[0].name,
                    u'rounding':
                    0.01,
                    u'symbol':
                    uom_uom_default_uom[0].name,
                    u'rate':
                    round(1 / float(values['capacity']), 12),
                    u'factor':
                    float(values['capacity']),
                    u'active':
                    True
                }])
                values['sale_uom'] = uom_uom_default_uom[0].id
                values['purchase_uom'] = uom_uom_default_uom[0].id
                values['default_uom'] = uom_uom_default_uom[0].id
            if uom_default_uom:
                Uom.write(uom_uom_default_uom, uom_default_uom)
            if 'party' in values:
                lvc['party'] = values['party']
                values.pop('party')
            if lvc != {}:
                product_suppliers.write(product_supplier, lvc)
            if 'code' in values:
                UomCategory.write(uom_category, {
                    'name':
                    uom_category[0].name.split('/')[0] + values['name']
                })
                lv['code'] = values['code']
                values.pop('code')
            if 'template' in values:
                lv['template'] = values[mark]
                values.pop('template')
            if lv != {}:
                product_products.write(product_product, lv)
            if 'mark' in values:
                values.pop('mark')
            if 'categories' in values:
                values['categories'] = [[
                    u'add', [values['categories']]
                ], [u'remove', [product_template[0].categories[0].id]]]
            if values != {}:
                product_templates.write(product_template, values)
            if 'sale_uom' in values:
                values.pop('sale_uom')
            if 'purchase_uom' in values:
                values.pop('purchase_uom')
        return super(New_products, cls).write(records, values)
Example #26
0
class Sale:
    "Sale"
    __name__ = 'sale.sale'

    is_international_shipping = fields.Function(
        fields.Boolean("Is International Shipping"),
        'on_change_with_is_international_shipping')

    weight = fields.Function(
        fields.Float(
            "Weight",
            digits=(16, Eval('weight_digits', 2)),
            depends=['weight_digits'],
        ), 'get_weight')

    weight_uom = fields.Function(fields.Many2One('product.uom', 'Weight UOM'),
                                 'get_weight_uom')
    weight_digits = fields.Function(fields.Integer('Weight Digits'),
                                    'on_change_with_weight_digits')

    available_carrier_services = fields.Function(
        fields.One2Many("carrier.service", None, 'Available Carrier Services'),
        getter="on_change_with_available_carrier_services")
    carrier_service = fields.Many2One(
        "carrier.service",
        "Carrier Service",
        domain=[('id', 'in', Eval('available_carrier_services'))],
        states={
            "invisible": Not(Bool(Eval('carrier'))),
            "readonly": Eval('state') != 'draft',
        },
        depends=['carrier', 'available_carrier_services', 'state'])
    carrier_cost_method = fields.Function(
        fields.Char('Carrier Cost Method'),
        "on_change_with_carrier_cost_method")

    @classmethod
    @ModelView.button_action('shipping.wizard_sale_apply_shipping')
    def apply_shipping(cls, sales):
        pass

    @fields.depends("carrier")
    def on_change_with_carrier_cost_method(self, name=None):
        if self.carrier:
            return self.carrier.carrier_cost_method

    def on_change_lines(self):
        """Pass a flag in context which indicates the get_sale_price method
        of carrier not to calculate cost on each line change
        """
        with Transaction().set_context({'ignore_carrier_computation': True}):
            super(Sale, self).on_change_lines()

    @fields.depends("carrier")
    def on_change_with_available_carrier_services(self, name=None):
        if self.carrier:
            return map(int, self.carrier.services)
        return []

    @classmethod
    def __setup__(cls):
        super(Sale, cls).__setup__()
        cls._error_messages.update({
            'warehouse_address_missing':
            'Warehouse address is missing',
        })
        cls._buttons.update({
            'apply_shipping': {
                "invisible":
                ~Eval('state').in_(['draft', 'quotation', 'confirmed'])
            }
        })
        cls.__rpc__.update({'apply_shipping_rate': RPC(instantiate=0)})

    @fields.depends('weight_uom')
    def on_change_with_weight_digits(self, name=None):
        if self.weight_uom:
            return self.weight_uom.digits
        return 2

    def get_weight_uom(self, name):
        """
        Returns weight uom for the sale
        """
        ModelData = Pool().get('ir.model.data')

        return ModelData.get_id('product', 'uom_pound')

    def get_weight(self, name):
        """
        Returns sum of weight associated with each line
        """
        return sum(
            map(lambda line: line.get_weight(self.weight_uom, silent=True),
                self.lines))

    @fields.depends('party', 'shipment_address', 'warehouse')
    def on_change_with_is_international_shipping(self, name=None):
        """
        Return True if international shipping
        """
        from_address = self._get_ship_from_address(silent=True)

        if self.shipment_address and from_address and \
                from_address.country and self.shipment_address.country and \
                from_address.country != self.shipment_address.country:
            return True
        return False

    def _get_ship_from_address(self, silent=False):
        """
        Usually the warehouse from which you ship
        """
        if not self.warehouse.address and not silent:
            return self.raise_user_error('warehouse_address_missing')
        return self.warehouse and self.warehouse.address

    def add_shipping_line(self,
                          shipment_cost,
                          description,
                          carrier=None,
                          carrier_service=None):
        """
        This method takes shipping_cost and description as arguments and writes
        a shipping line. It deletes any previous shipping lines which have
        a shipment_cost.
        :param shipment_cost: The shipment cost calculated according to carrier
        :param description: Shipping line description
        """
        Sale = Pool().get('sale.sale')

        carrier = carrier or self.carrier
        carrier_service = carrier_service and self.carrier_service

        Sale.write(
            [self],
            {
                'lines': [
                    (
                        'create',
                        [{
                            'type': 'line',
                            'product': carrier.carrier_product.id,
                            'description': description,
                            'quantity': 1,  # XXX
                            'unit': carrier.carrier_product.sale_uom.id,
                            'unit_price': shipment_cost,
                            'shipment_cost': shipment_cost,
                            'amount': shipment_cost,
                            'taxes': [],
                            'sequence': 9999,  # XXX
                        }]),
                    ('delete', [
                        line for line in self.lines
                        if line.shipment_cost is not None
                    ]),
                ],
                # reset the amount caches or function
                # fields will continue to return cached values
                'untaxed_amount_cache':
                None,
                'tax_amount_cache':
                None,
                'total_amount_cache':
                None,
            })
        # reset the order total cache
        if self.state not in ('draft', 'quote'):
            Sale.store_cache([self])

    def _get_carrier_context(self):
        "Pass sale in the context"
        context = super(Sale, self)._get_carrier_context()
        context = context.copy()
        context['sale'] = self.id
        return context

    def apply_shipping_rate(self, rate):
        """
        This method applies shipping rate. Rate is a dictionary with following
        minimum keys:

            {
                'display_name': Name to display,
                'carrier_service': carrier.service active record,
                'cost': cost,
                'cost_currency': currency.currency active record,
                'carrier': carrier active record,
            }

        It also creates a shipment line by deleting all existing ones.

        The rate could optionally have integer ids of service, carrier and
        currency.
        """
        Currency = Pool().get('currency.currency')
        Carrier = Pool().get('carrier')
        CarrierService = Pool().get('carrier.service')

        self.carrier = Carrier(int(rate['carrier']))
        self.carrier_service = CarrierService(int(rate['carrier_service'])) \
            if rate['carrier_service'] else None
        self.save()

        cost_currency = Currency(int(rate['cost_currency']))
        shipment_cost = cost_currency.round(rate['cost'])
        if self.currency != cost_currency:
            shipment_cost = Currency.compute(cost_currency, shipment_cost,
                                             self.currency)

        self.add_shipping_line(
            shipment_cost,
            rate['display_name'],
            self.carrier,
            self.carrier_service,
        )

    def get_shipping_rates(self, carriers=None, silent=False):
        """
        Gives a list of rates from carriers provided. If no carriers provided,
        return rates from all the carriers.

        List contains dictionary with following minimum keys:
            [
                {
                    'display_name': Name to display,
                    'carrier_service': carrier.service active record,
                    'cost': cost,
                    'cost_currency': currency.currency active repord,
                    'carrier': carrier active record,
                }..
            ]
        """
        Carrier = Pool().get('carrier')

        if carriers is None:
            carriers = Carrier.search([])

        rates = []
        for carrier in carriers:
            rates.extend(self.get_shipping_rate(carrier, silent=silent))
        return rates

    def get_shipping_rate(self, carrier, carrier_service=None, silent=False):
        """
        Gives a list of rates from provided carrier and carrier service.

        List contains dictionary with following minimum keys:
            [
                {
                    'display_name': Name to display,
                    'carrier_service': carrier.service active record,
                    'cost': cost,
                    'cost_currency': currency.currency active repord,
                    'carrier': carrier active record,
                }..
            ]
        """
        Company = Pool().get('company.company')

        if carrier.carrier_cost_method == 'product':
            currency = Company(Transaction().context['company']).currency
            rate_dict = {
                'carrier_service': carrier_service,
                'cost': carrier.carrier_product.list_price,
                'cost_currency': currency,
                'carrier': carrier,
            }
            display_name = carrier.rec_name
            rate_dict['display_name'] = display_name
            return [rate_dict]

        return []

    @classmethod
    def get_allowed_carriers_domain(cls):
        """This method returns domain to seach allowed carriers

        Downstream modules can inherit and update customize this domain.
        """
        return []

    def create_shipment(self, shipment_type):
        with Transaction().set_context(ignore_carrier_computation=True):
            shipments = super(Sale, self).create_shipment(shipment_type)

        if shipment_type == 'out' and shipments:
            for shipment in shipments:
                if shipment.carrier:
                    continue
                shipment.carrier = self.carrier
                shipment.carrier_service = self.carrier_service
                shipment.save()

        return shipments
Example #27
0
class ActionReport(ActionMixin, ModelSQL, ModelView):
    "Action report"
    __name__ = 'ir.action.report'
    _action_name = 'report_name'
    model = fields.Char('Model')
    report_name = fields.Char('Internal Name', required=True)
    report = fields.Char("Path",
                         states={
                             'invisible': Eval('is_custom', False),
                         },
                         depends=['is_custom'])
    report_content_custom = fields.Binary('Content')
    is_custom = fields.Function(fields.Boolean("Is Custom"), 'get_is_custom')
    report_content = fields.Function(fields.Binary(
        'Content', filename='report_content_name'),
                                     'get_report_content',
                                     setter='set_report_content')
    report_content_name = fields.Function(
        fields.Char('Content Name'), 'on_change_with_report_content_name')
    report_content_html = fields.Function(fields.Binary(
        "Content HTML",
        states={
            'invisible': ~Eval('template_extension').in_(['html', 'xhtml']),
        },
        depends=['template_extension']),
                                          'get_report_content_html',
                                          setter='set_report_content_html')
    action = fields.Many2One('ir.action',
                             'Action',
                             required=True,
                             ondelete='CASCADE')
    direct_print = fields.Boolean('Direct Print')
    single = fields.Boolean(
        "Single", help="Check if the template works only for one record.")
    translatable = fields.Boolean(
        "Translatable",
        help="Uncheck to disable translations for this report.")
    template_extension = fields.Selection([
        ('odt', 'OpenDocument Text'),
        ('odp', 'OpenDocument Presentation'),
        ('ods', 'OpenDocument Spreadsheet'),
        ('odg', 'OpenDocument Graphics'),
        ('txt', 'Plain Text'),
        ('xml', 'XML'),
        ('html', 'HTML'),
        ('xhtml', 'XHTML'),
    ],
                                          string='Template Extension',
                                          required=True,
                                          translate=False)
    extension = fields.Selection(
        [
            ('', ''),
            ('bib', 'BibTex'),
            ('bmp', 'Windows Bitmap'),
            ('csv', 'Text CSV'),
            ('dbf', 'dBase'),
            ('dif', 'Data Interchange Format'),
            ('doc', 'Microsoft Word 97/2000/XP'),
            ('doc6', 'Microsoft Word 6.0'),
            ('doc95', 'Microsoft Word 95'),
            ('docbook', 'DocBook'),
            ('docx', 'Microsoft Office Open XML Text'),
            ('docx7', 'Microsoft Word 2007 XML'),
            ('emf', 'Enhanced Metafile'),
            ('eps', 'Encapsulated PostScript'),
            ('gif', 'Graphics Interchange Format'),
            ('html', 'HTML Document'),
            ('jpg', 'Joint Photographic Experts Group'),
            ('met', 'OS/2 Metafile'),
            ('ooxml', 'Microsoft Office Open XML'),
            ('pbm', 'Portable Bitmap'),
            ('pct', 'Mac Pict'),
            ('pdb', 'AportisDoc (Palm)'),
            ('pdf', 'Portable Document Format'),
            ('pgm', 'Portable Graymap'),
            ('png', 'Portable Network Graphic'),
            ('ppm', 'Portable Pixelmap'),
            ('ppt', 'Microsoft PowerPoint 97/2000/XP'),
            ('psw', 'Pocket Word'),
            ('pwp', 'PlaceWare'),
            ('pxl', 'Pocket Excel'),
            ('ras', 'Sun Raster Image'),
            ('rtf', 'Rich Text Format'),
            ('latex', 'LaTeX 2e'),
            ('sda', 'StarDraw 5.0 (OpenOffice.org Impress)'),
            ('sdc', 'StarCalc 5.0'),
            ('sdc4', 'StarCalc 4.0'),
            ('sdc3', 'StarCalc 3.0'),
            ('sdd', 'StarImpress 5.0'),
            ('sdd3', 'StarDraw 3.0 (OpenOffice.org Impress)'),
            ('sdd4', 'StarImpress 4.0'),
            ('sdw', 'StarWriter 5.0'),
            ('sdw4', 'StarWriter 4.0'),
            ('sdw3', 'StarWriter 3.0'),
            ('slk', 'SYLK'),
            ('svg', 'Scalable Vector Graphics'),
            ('svm', 'StarView Metafile'),
            ('swf', 'Macromedia Flash (SWF)'),
            ('sxc', 'OpenOffice.org 1.0 Spreadsheet'),
            ('sxi', 'OpenOffice.org 1.0 Presentation'),
            ('sxd', 'OpenOffice.org 1.0 Drawing'),
            ('sxd3', 'StarDraw 3.0'),
            ('sxd5', 'StarDraw 5.0'),
            ('sxw', 'Open Office.org 1.0 Text Document'),
            ('text', 'Text Encoded'),
            ('tiff', 'Tagged Image File Format'),
            ('txt', 'Plain Text'),
            ('wmf', 'Windows Metafile'),
            ('xhtml', 'XHTML Document'),
            ('xls', 'Microsoft Excel 97/2000/XP'),
            ('xls5', 'Microsoft Excel 5.0'),
            ('xls95', 'Microsoft Excel 95'),
            ('xlsx', 'Microsoft Excel 2007/2010 XML'),
            ('xpm', 'X PixMap'),
        ],
        translate=False,
        string='Extension',
        help='Leave empty for the same as template, '
        'see LibreOffice documentation for compatible format.')
    module = fields.Char('Module', readonly=True, select=True)
    _template_cache = MemoryCache('ir.action.report.template', context=False)

    @classmethod
    def __register__(cls, module_name):
        super(ActionReport, cls).__register__(module_name)

        transaction = Transaction()
        cursor = transaction.connection.cursor()
        table = cls.__table_handler__(module_name)
        action_report = cls.__table__()

        # Migration from 3.4 remove report_name_module_uniq constraint
        table.drop_constraint('report_name_module_uniq')

        # Migration from 4.4 replace plain extension by txt
        cursor.execute(
            *action_report.update([action_report.extension], ['txt'],
                                  where=action_report.extension == 'plain'))

    @staticmethod
    def default_type():
        return 'ir.action.report'

    @staticmethod
    def default_report_content():
        return None

    @staticmethod
    def default_direct_print():
        return False

    @classmethod
    def default_single(cls):
        return False

    @classmethod
    def default_translatable(cls):
        return True

    @staticmethod
    def default_template_extension():
        return 'odt'

    @staticmethod
    def default_extension():
        return ''

    @staticmethod
    def default_module():
        return Transaction().context.get('module') or ''

    def get_is_custom(self, name):
        return bool(self.report_content_custom)

    @classmethod
    def get_report_content(cls, reports, name):
        contents = {}
        converter = fields.Binary.cast
        default = None
        format_ = Transaction().context.get('%s.%s' % (cls.__name__, name), '')
        if format_ == 'size':
            converter = len
            default = 0
        for report in reports:
            data = getattr(report, name + '_custom')
            if not data and getattr(report, name[:-8]):
                try:
                    with file_open(getattr(report,
                                           name[:-8]).replace('/', os.sep),
                                   mode='rb') as fp:
                        data = fp.read()
                except Exception:
                    data = None
            contents[report.id] = converter(data) if data else default
        return contents

    @classmethod
    def set_report_content(cls, records, name, value):
        cls.write(records, {'%s_custom' % name: value})

    @classmethod
    def get_report_content_html(cls, reports, name):
        return cls.get_report_content(reports, name[:-5])

    @classmethod
    def set_report_content_html(cls, reports, name, value):
        if value is not None:
            value = value.encode('utf-8')
        cls.set_report_content(reports, name[:-5], value)

    @fields.depends('name', 'template_extension')
    def on_change_with_report_content_name(self, name=None):
        return ''.join(
            filter(None, [self.name, os.extsep, self.template_extension]))

    @classmethod
    def get_pyson(cls, reports, name):
        pysons = {}
        field = name[6:]
        defaults = {}
        for report in reports:
            pysons[report.id] = (getattr(report, field)
                                 or defaults.get(field, 'null'))
        return pysons

    @classmethod
    def copy(cls, reports, default=None):
        if default is None:
            default = {}
        default = default.copy()
        default.setdefault('module', None)

        new_reports = []
        for report in reports:
            if report.report:
                default['report_content'] = None
                default['report'] = None
            default['report_name'] = report.report_name
            new_reports.extend(
                super(ActionReport, cls).copy([report], default=default))
        return new_reports

    @classmethod
    def write(cls, reports, values, *args):
        context = Transaction().context
        if 'module' in context:
            actions = iter((reports, values) + args)
            args = []
            for reports, values in zip(actions, actions):
                values = values.copy()
                values['module'] = context['module']
                args.extend((reports, values))
            reports, values = args[:2]
            args = args[2:]
        cls._template_cache.clear()
        super(ActionReport, cls).write(reports, values, *args)

    def get_template_cached(self):
        return self._template_cache.get(self.id)

    def set_template_cached(self, template):
        self._template_cache.set(self.id, template)
Example #28
0
class ShipmentOut():
    __metaclass__ = PoolMeta
    __name__ = 'stock.shipment.out'

    remision = fields.Boolean(u'Enviar Guía de Remisión al SRI',
                              states={
                                  'readonly': Eval('state') == 'done',
                              })
    placa = fields.Char('Placa del medio de Transporte',
                        states={
                            'invisible': ~Eval('remision', False),
                            'required': Eval('remision', True),
                            'readonly': Eval('state') == 'done',
                        })
    cod_estab_destino = fields.Char(u'Código de establecimiento de Destino',
                                    size=3,
                                    states={
                                        'invisible': ~Eval('remision', False),
                                        'required': Eval('remision', True),
                                        'readonly': Eval('state') == 'done',
                                    })
    ruta = fields.Char('Ruta',
                       states={
                           'invisible': ~Eval('remision', False),
                           'required': Eval('remision', True),
                           'readonly': Eval('state') == 'done',
                       })
    partida = fields.Char('Direccion de partida',
                          states={
                              'invisible': ~Eval('remision', False),
                              'required': Eval('remision', True),
                              'readonly': Eval('state') == 'done',
                          })
    estado_sri = fields.Char(u'Estado Comprobante-Electrónico',
                             size=24,
                             readonly=True,
                             states={
                                 'invisible': ~Eval('remision', False),
                                 'required': Eval('remision', True),
                                 'readonly': Eval('state') == 'done',
                             })
    number_c = fields.Char(u'Número del Documento de Sustento',
                           size=17,
                           states={
                               'invisible': ~Eval('remision', False),
                               'required': Eval('remision', True),
                               'readonly': Eval('state') == 'done',
                           })
    path_xml = fields.Char(u'Path archivo xml de comprobante', readonly=True)
    path_pdf = fields.Char(u'Path archivo pdf de factura', readonly=True)
    numero_autorizacion = fields.Char(u'Número de Autorización', readonly=True)
    transporte = fields.Many2One('carrier',
                                 'Transportista',
                                 states={
                                     'invisible': ~Eval('remision', False),
                                     'required': Eval('remision', True),
                                     'readonly': Eval('state') == 'done',
                                 })

    @classmethod
    def __setup__(cls):
        super(ShipmentOut, cls).__setup__()
        cls.effective_date.states['required'] = Eval('remision', True)
        cls.planned_date.states['required'] = Eval('remision', True)

    #metodo para asignar impuesto
    @fields.depends('moves', 'remision', 'number_c')
    def on_change_remision(self):
        venta = None
        invoices = None
        invoice = None
        if self.remision == True:
            for s in self.moves:
                venta = s.sale
            pool = Pool()
            Invoice = pool.get('account.invoice')
            invoices = Invoice.search([('description', '=', venta.reference)])
            if invoices:
                for i in invoices:
                    invoice = i
            if invoice:
                self.number_c = invoice.number
            else:
                self.number_c = None

    @classmethod
    @ModelView.button
    @Workflow.transition('done')
    def done(cls, shipments):
        pool = Pool()
        Move = pool.get('stock.move')
        Date = pool.get('ir.date')

        for shipment in shipments:
            if shipment.remision == True:
                shipment.get_tax_element()
                shipment.get_shipment_element()
                shipment.get_destinatarios()
                shipment.generate_xml_shipment()
                shipment.action_generate_shipment()
                shipment.connect_db()
        Move.do([m for s in shipments for m in s.outgoing_moves])
        cls.write([s for s in shipments if not s.effective_date], {
            'effective_date': Date.today(),
        })

    def web_service(self):
        CONEXION = 'UD NO HA CONFIGURADO LOS DATOS DE CONEXION CON EL WS, \nCOMUNIQUESE CON EL ADMINISTRADOR DEL SISTEMA'
        pool = Pool()
        conexions = pool.get('res.user')
        conexion = conexions.search([('id', '=', 1)])
        if conexion:
            for c in conexion:
                if c.direccion:
                    address = c.cabecera + "://" + base64.decodestring(
                        c.usuario
                    ) + ":" + base64.decodestring(
                        c.pass_db
                    ) + "@" + c.direccion + ":" + c.puerto + "/" + base64.decodestring(
                        c.name_db)
                return address
        else:
            self.raise_user_error(CONEXION)

    def connect_db(self):
        address_xml = self.web_service()
        s = xmlrpclib.ServerProxy(address_xml)
        pool = Pool()
        nombre = self.customer.name
        cedula = self.customer.vat_number
        ruc = self.company.party.vat_number
        nombre_e = self.company.party.name
        tipo = 'out_shipment'
        fecha = str(self.effective_date)
        empresa = self.company.party.name
        numero = self.code
        path_xml = self.path_xml
        path_pdf = self.path_pdf
        estado = self.estado_sri
        auth = self.numero_autorizacion
        correos = pool.get('party.contact_mechanism')
        correo = correos.search([('type', '=', 'email')])
        for c in correo:
            if c.party == self.customer:
                to_email = c.value
            if c.party == self.company.party:
                to_email_2 = c.value
        email_e = to_email_2
        email = to_email
        total = ''
        s.model.nodux_electronic_invoice_auth.conexiones.connect_db(
            nombre, cedula, ruc, nombre_e, tipo, fecha, empresa, numero,
            path_xml, path_pdf, estado, auth, email, email_e, total, {})

    def send_mail_invoice(self,
                          xml_element,
                          access_key,
                          send_m,
                          s,
                          server="localhost"):
        MAIL = u"Ud no ha configurado el correo del cliente. Diríjase a: \nTerceros->General->Medios de Contacto"
        pool = Pool()
        empresa = self.elimina_tildes(self.company.party.name)
        #empresa = unicode(empresa, 'utf-8')
        empresa = str(self.elimina_tildes(empresa))
        empresa = empresa.replace(' ', '_')
        empresa = empresa.lower()

        ahora = datetime.datetime.now()
        year = str(ahora.year)
        client = self.customer.name
        client = client.upper()
        empresa_ = self.company.party.name
        ruc = self.company.party.vat_number

        if ahora.month < 10:
            month = '0' + str(ahora.month)
        else:
            month = str(ahora.month)
        tipo = 'rem_'
        n_tipo = "GUIA DE REMISION"

        ruc = access_key[10:23]
        est = access_key[24:27]
        emi = access_key[27:30]
        sec = access_key[30:39]
        num_fac = est + '-' + emi + '-' + sec
        numero = ruc + '_' + num_fac
        name_pdf = tipo + numero + '.pdf'
        name_xml = tipo + numero + '.xml'
        #nuevaruta =os.getcwd() +'/comprobantes/'+empresa+'/'+year+'/'+month +'/'
        nr = s.model.nodux_electronic_invoice_auth.conexiones.path_files(
            ruc, {})
        nuevaruta = nr + empresa + '/' + year + '/' + month + '/'

        new_save = 'comprobantes/' + empresa + '/' + year + '/' + month + '/'
        self.write(
            [self], {
                'estado_sri': 'AUTORIZADO',
                'path_xml': new_save + name_xml,
                'numero_autorizacion': access_key,
                'path_pdf': new_save + name_pdf
            })

        correos = pool.get('party.contact_mechanism')
        correo = correos.search([('type', '=', 'email')])
        InvoiceReport = Pool().get('stock.shipment.out.print_shipment_e',
                                   type='report')
        report = InvoiceReport.execute([self.id], {})

        email = ''
        cont = 0
        for c in correo:
            if c.party == self.customer:
                email = c.value
            if c.party == self.company.party:
                f_e = c.value

        if email != '':
            to_email = email
        else:
            self.raise_user_error(MAIL)

        if send_m == '1':
            from_email = f_e
        else:
            from_email = "*****@*****.**"

        name = access_key + ".xml"
        reporte = xmlrpclib.Binary(report[1])
        xml_element = unicode(xml_element, 'utf-8')
        xml_element = self.elimina_tildes(xml_element)
        xml = xmlrpclib.Binary(xml_element.replace('><', '>\n<'))

        save_files = s.model.nodux_electronic_invoice_auth.conexiones.save_file(
            empresa, name_pdf, name_xml, reporte, xml, {})
        p_xml = nuevaruta + name_xml
        p_pdf = nuevaruta + name_pdf
        s.model.nodux_electronic_invoice_auth.conexiones.send_mail(
            name_pdf, name, p_xml, p_pdf, from_email, to_email, n_tipo,
            num_fac, client, empresa_, ruc, {})

        return True

    def elimina_tildes(self, s):
        return ''.join((c for c in unicodedata.normalize('NFD', s)
                        if unicodedata.category(c) != 'Mn'))

    def generate_access_key(self):
        fecha = self.create_date.strftime('%d%m%Y')
        tipo_cbte = '06'
        ruc = self.company.party.vat_number
        tipo_amb = '1'
        num_cbte = self.code
        cod_num = "13245768"
        tipo_emision = self.company.emission_code
        numero_cbte = num_cbte.replace('-', '')
        #unimos todos los datos en una sola cadena
        clave_inicial = fecha + tipo_cbte + ruc + tipo_amb + numero_cbte + cod_num + tipo_emision
        #recorremos la cadena para ir guardando en una lista de enteros
        clave = []
        for c in clave_inicial:
            clave.append(int(c))
        clave.reverse()
        factor = [2, 3, 4, 5, 6, 7]
        etapa1 = sum([n * factor[i % 6] for i, n in enumerate(clave)])
        etapa2 = etapa1 % 11
        digito = 11 - (etapa2)
        if digito == 11:
            digito = 0
        if digito == 10:
            digito = 1
        digito = str(digito)
        clave_acceso = clave_inicial + digito
        return clave_acceso

    def get_tax_element(self):
        """
        """
        company = self.company
        number = self.code
        #auth = self.journal_id.auth_id
        infoTributaria = etree.Element('infoTributaria')
        etree.SubElement(infoTributaria, 'ambiente').text = "1"
        #SriService.get_active_env()

        etree.SubElement(infoTributaria,
                         'tipoEmision').text = self.company.emission_code
        etree.SubElement(infoTributaria,
                         'razonSocial').text = self.company.party.name
        if self.company.party.commercial_name:
            etree.SubElement(
                infoTributaria,
                'nombreComercial').text = self.company.party.commercial_name
        else:
            etree.SubElement(infoTributaria,
                             'nombreComercial').text = self.company.party.name
        etree.SubElement(infoTributaria,
                         'ruc').text = self.company.party.vat_number
        etree.SubElement(infoTributaria,
                         'claveAcceso').text = self.generate_access_key()
        etree.SubElement(infoTributaria, 'codDoc').text = "06"
        etree.SubElement(infoTributaria, 'estab').text = number[0:3]
        etree.SubElement(infoTributaria, 'ptoEmi').text = number[4:7]
        etree.SubElement(infoTributaria, 'secuencial').text = number[8:17]
        if self.company.party.addresses:
            etree.SubElement(
                infoTributaria,
                'dirMatriz').text = self.company.party.addresses[0].street
        return infoTributaria

    def get_shipment_element(self):

        company = self.company
        customer = self.customer
        infoGuiaRemision = etree.Element('infoGuiaRemision')
        if self.company.party.addresses:
            etree.SubElement(infoGuiaRemision, 'dirEstablecimiento'
                             ).text = self.company.party.addresses[0].street
        if self.company.party.addresses:
            etree.SubElement(infoGuiaRemision,
                             'dirPartida').text = self.partida
        etree.SubElement(
            infoGuiaRemision,
            'razonSocialTransportista').text = self.transporte.party.name
        etree.SubElement(
            infoGuiaRemision,
            'tipoIdentificacionTransportista').text = tipoIdentificacion[
                self.transporte.party.type_document]
        etree.SubElement(
            infoGuiaRemision,
            'rucTransportista').text = self.transporte.party.vat_number
        etree.SubElement(infoGuiaRemision, 'rise').text = "No  obligatorios"
        if self.company.party.mandatory_accounting:
            etree.SubElement(infoGuiaRemision, 'obligadoContabilidad'
                             ).text = self.company.party.mandatory_accounting
        else:
            etree.SubElement(infoGuiaRemision,
                             'obligadoContabilidad').text = 'NO'

        if self.company.party.contribuyente_especial_nro:
            etree.SubElement(
                infoGuiaRemision, 'contribuyenteEspecial'
            ).text = self.company.party.contribuyente_especial_nro
        etree.SubElement(
            infoGuiaRemision,
            'fechaIniTransporte').text = self.planned_date.strftime('%d/%m/%Y')
        etree.SubElement(
            infoGuiaRemision,
            'fechaFinTransporte').text = self.planned_date.strftime('%d/%m/%Y')
        etree.SubElement(infoGuiaRemision, 'placa').text = self.placa
        return infoGuiaRemision

    def get_destinatarios(self):
        ERROR = u"No existe factura registrada con el número que ingresó"
        num_mod = self.number_c
        pool = Pool()
        Invoices = pool.get('account.invoice')
        invoice = Invoices.search([('number', '=', num_mod)])
        if invoice:
            pass
        else:
            self.raise_user_error(ERROR)
        for i in invoice:
            date_mod = i.invoice_date.strftime('%d/%m/%Y')
            num_aut = i.numero_autorizacion

        company = self.company
        customer = self.customer
        destinatarios = etree.Element('destinatarios')
        destinatario = etree.Element('destinatario')
        etree.SubElement(
            destinatario,
            'identificacionDestinatario').text = self.customer.vat_number
        etree.SubElement(destinatario,
                         'razonSocialDestinatario').text = self.customer.name
        etree.SubElement(destinatario,
                         'dirDestinatario').text = self.dir_destinatario
        etree.SubElement(destinatario,
                         'motivoTraslado').text = self.motivo_traslado
        etree.SubElement(destinatario, 'docAduaneroUnico').text = " "
        etree.SubElement(destinatario,
                         'codEstabDestino').text = self.cod_estab_destino
        etree.SubElement(destinatario, 'ruta').text = self.ruta
        etree.SubElement(destinatario, 'codDocSustento').text = "01"
        etree.SubElement(destinatario, 'numDocSustento').text = num_mod
        if num_aut:
            #etree.SubElement(destinatario, 'numAutDocSustento').text = num_aut
            print "Si hay autorizacion"
        etree.SubElement(
            destinatario, 'fechaEmisionDocSustento'
        ).text = date_mod  #self.create_date.strftime('%d/%m/%Y')

        detalles = etree.Element('detalles')

        def fix_chars(code):
            if code:
                code.replace(u'%',
                             ' ').replace(u'º',
                                          ' ').replace(u'Ñ',
                                                       'N').replace(u'ñ', 'n')
                return code
            return '1'

        detalle = etree.Element('detalle')
        for move in self.moves:
            move = move
        etree.SubElement(detalle,
                         'codigoInterno').text = fix_chars(move.product.code)
        etree.SubElement(detalle,
                         'descripcion').text = fix_chars(move.product.name)
        etree.SubElement(detalle, 'cantidad').text = str(move.quantity)
        detalles.append(detalle)
        destinatario.append(detalles)
        destinatarios.append(destinatario)
        return destinatarios

    def generate_xml_shipment(self):
        guiaRemision = etree.Element('guiaRemision')
        guiaRemision.set("id", "comprobante")
        guiaRemision.set("version", "1.1.0")

        #generar infoTributaria
        infoTributaria = self.get_tax_element()
        guiaRemision.append(infoTributaria)

        #generar infoGuiaRemision
        infoGuiaRemision = self.get_shipment_element()
        guiaRemision.append(infoGuiaRemision)

        #generar destinatarios
        destinatarios = self.get_destinatarios()
        guiaRemision.append(destinatarios)

        return guiaRemision

    def check_before_sent(self):
        """
        """
        sql = "select autorizado_sri, number from account_invoice where state='open' and number < '%s' order by number desc limit 1" % self.number
        self.execute(sql)
        res = self.fetchone()
        return res[0] and True or False

    def action_generate_shipment(self):

        PK12 = u'No ha configurado los datos de la empresa. Dirijase a: \n Empresa -> NODUX WS'
        AUTHENTICATE_ERROR = u'Error en datos de ingreso verifique: \nUSARIO Y CONTRASEÑA'
        ACTIVE_ERROR = u"Ud. no se encuentra activo, verifique su pago. \nComuníquese con NODUX"
        WAIT_FOR_RECEIPT = 3
        TITLE_NOT_SENT = u'No se puede enviar el comprobante electronico al SRI'
        MESSAGE_SEQUENCIAL = u'Los comprobantes electrónicos deben ser enviados al SRI en orden secuencial'
        MESSAGE_TIME_LIMIT = u'Se ha excedido el límite de tiempo. Los comprobantes electrónicos deben \nser enviados al SRI, en un plazo máximo de 24 horas'

        #Validar que el envio del comprobante electronico se realice dentro de las 24 horas posteriores a su emision
        pool = Pool()
        Date = pool.get('ir.date')
        date_f = self.effective_date
        date = Date.today()
        limit = (date - date_f).days
        #if limit > 1:
        #   self.raise_user_error(MESSAGE_TIME_LIMIT)
        # Validar que el envio de los comprobantes electronicos sea secuencial
        #if not self.check_before_sent():
        #self.raise_user_error(TITLE_NOT_SENT, MESSAGE_SEQUENCIAL)

        usuario = self.company.user_ws
        password_u = self.company.password_ws
        access_key = self.generate_access_key()
        address_xml = self.web_service()
        s = xmlrpclib.ServerProxy(address_xml)

        name = self.company.party.name
        name_l = name.lower()
        name_r = name_l.replace(' ', '_').replace(u'á', 'a').replace(
            u'é', 'e').replace(u'í', 'i').replace(u'ó',
                                                  'o').replace(u'ú', 'u')
        name_c = name_r + '.p12'
        """
        if self.company.file_pk12:
            archivo = self.company.file_pk12
        else :
            self.raise_user_error(PK12)
        f = open(name_c, 'wb')
        f.write(archivo)
        f.close()
        """

        authenticate, send_m, active = s.model.nodux_electronic_invoice_auth.conexiones.authenticate(
            usuario, password_u, {})
        if authenticate == '1':
            pass
        else:
            self.raise_user_error(AUTHENTICATE_ERROR)
        if active == '1':
            self.raise_user_error(ACTIVE_ERROR)
        else:
            pass

        nuevaruta = s.model.nodux_electronic_invoice_auth.conexiones.save_pk12(
            name_l, {})
        """
        shutil.copy2(name_c, nuevaruta)
        os.remove(name_c)
        print etree.tostring(guiaRemision1,pretty_print=True ,xml_declaration=True, encoding="utf-8")
        """
        guiaRemision1 = self.generate_xml_shipment()
        guiaRemision = etree.tostring(guiaRemision1,
                                      encoding='utf8',
                                      method='xml')
        #validacion del xml (llama metodo validate xml de sri)
        a = s.model.nodux_electronic_invoice_auth.conexiones.validate_xml(
            guiaRemision, 'out_shipment', {})
        if a:
            self.raise_user_error(a)
        file_pk12 = base64.encodestring(nuevaruta + '/' + name_c)
        file_check = (nuevaruta + '/' + name_c)
        password = self.company.password_pk12
        error = s.model.nodux_electronic_invoice_auth.conexiones.check_digital_signature(
            file_check, {})
        if error == '1':
            self.raise_user_error(
                'No se ha encontrado el archivo de firma digital (.p12)')

        signed_document = s.model.nodux_electronic_invoice_auth.conexiones.apply_digital_signature(
            guiaRemision, file_pk12, password, {})

        #envio al sri para recepcion del comprobante electronico
        result = s.model.nodux_electronic_invoice_auth.conexiones.send_receipt(
            signed_document, {})
        if result != True:
            self.raise_user_error(result)
        time.sleep(WAIT_FOR_RECEIPT)
        # solicitud al SRI para autorizacion del comprobante electronico
        doc_xml, m, auth, path, numero, num = s.model.nodux_electronic_invoice_auth.conexiones.request_authorization(
            access_key, name_r, 'out_shipment', signed_document, {})
        if doc_xml is None:
            msg = ' '.join(m)
            raise m

        if auth == 'NO AUTORIZADO':
            self.write([self], {'estado_sri': 'NO AUTORIZADO'})
        else:
            pass
        self.send_mail_invoice(doc_xml, access_key, send_m, s)

        return access_key

    def action_generate_lote_shipment(self):
        """
        """
        LIMIT_TO_SEND = 5
        WAIT_FOR_RECEIPT = 3
        TITLE_NOT_SENT = u'No se puede enviar el comprobante electronico al SRI'
        MESSAGE_SEQUENCIAL = u'Los comprobantes electronicos deben ser enviados al SRI en orden secuencial'
        MESSAGE_TIME_LIMIT = u'Los comprobantes electronicos deben ser enviados al SRI para su autorizacion, en un plazo maximo de 24 horas'

        if not self.type in ['out_shipment']:
            print "no disponible para otros documentos"
            pass
        access_key = self.generate_access_key_lote()
        if self.type == 'out_shipment':
            # XML del comprobante electronico: factura
            lote = self.generate_xml_lote_shipment()
            #validacion del xml (llama metodo validate xml de sri)
            inv_xml = DocumentXML(lote, 'lote')
            inv_xml.validate_xml()
            # solicitud de autorizacion del comprobante electronico
            xmlstr = etree.tostring(lote, encoding='utf8', method='xml')
            inv_xml.send_receipt(xmlstr)
            time.sleep(WAIT_FOR_RECEIPT)
            doc_xml, m, auth = inv_xml.request_authorization_lote(access_key)
            print "esta es la auth", auth

            if doc_xml is None:
                msg = ' '.join(m)
                raise m
            if auth == False:
                vals = {
                    'estado_sri': 'NO AUTORIZADO',
                }
            else:
                vals = {
                    'estado_sri': auth.estado,
                }
            self.write([self], vals)
            time.sleep(WAIT_FOR_RECEIPT)
            self.send_mail_invoice(doc_xml)

            if auth == False:
                self.raise_user_error('error', (m, ))
        return access_key

    def generate_xml_lote_shipment(self):
        pool = Pool()
        usuario = self.company.user_ws
        password_u = self.company.password_ws
        address_xml = self.web_service()
        s = xmlrpclib.ServerProxy(address_xml)
        name = self.company.party.name
        name_r = name.replace(' ', '_')
        name_l = name_r.lower()
        name_c = name_l + '.p12'
        if self.company.file_pk12:
            archivo = self.company.file_pk12
        else:
            self.raise_user_error(PK12)

        f = open(name_c, 'wb')
        f.write(archivo)
        f.close()
        authenticate, send_m = s.model.nodux_electronic_invoice_auth.conexiones.authenticate(
            usuario, password_u, {})
        if authenticate == '1':
            pass
        else:
            self.raise_user_error(AUTHENTICATE_ERROR)

        nuevaruta = s.model.nodux_electronic_invoice_auth.conexiones.save_pk12(
            name_l, {})
        shutil.copy2(name_c, nuevaruta)
        os.remove(name_c)
        file_pk12 = base64.encodestring(nuevaruta + '/' + name_c)
        password = base64.encodestring(self.company.password_pk12)

        Invoice = pool.get('account.invoice')
        invoices = Invoice.browse(Transaction().context['active_ids'])
        print invoices
        lote = etree.Element('lote')
        lote.set("version", "1.0.0")
        etree.SubElement(lote,
                         'claveAcceso').text = self.generate_access_key_lote()
        etree.SubElement(lote, 'ruc').text = self.company.party.vat_number
        comprobantes = etree.Element('comprobantes')
        for invoice in invoices:
            print "Factura ", invoice
            factura1 = invoice.generate_xml_invoice()
            factura = etree.tostring(factura1, encoding='utf8', method='xml')
            #print etree.tostring(factura1, pretty_print = True, xml_declaration=True, encoding="utf-8")
            signed_document = s.model.nodux_electronic_invoice_auth.conexiones.apply_digital_signature(
                factura, file_pk12, password, {})
            etree.SubElement(comprobantes,
                             'comprobante').text = etree.CDATA(signed_document)
        lote.append(comprobantes)
        print etree.tostring(lote,
                             pretty_print=True,
                             xml_declaration=True,
                             encoding="utf-8")
        return lote

        pool = Pool()
        xades = Xades()
        file_pk12 = base64.encodestring(self.company.electronic_signature)
        password = base64.encodestring(self.company.password_hash)
        Shipment = Pool().get('stock.shipment.out')
        shipments = Shipment.browse(Transaction().context['active_ids'])

        lote = etree.Element('lote')
        lote.set("version", "1.0.0")
        etree.SubElement(lote,
                         'claveAcceso').text = self.generate_access_key_lote()
        etree.SubElement(lote, 'ruc').text = self.company.party.vat_number
        comprobantes = etree.Element('comprobantes')
        for shipment in shipment:
            guiaRemision = self.generate_xml_shipment()
            signed_document = xades.apply_digital_signature(
                guiaRemision, file_pk12, password)
            print etree.tostring(guiaRemision,
                                 pretty_print=True,
                                 xml_declaration=True,
                                 encoding="utf-8")
            etree.SubElement(comprobantes,
                             'comprobante').text = etree.CDATA(signed_document)
        lote.append(comprobantes)
        return lote
Example #29
0
class Newborn(ModelSQL, ModelView):
    'Newborn Information'
    __name__ = 'gnuhealth.newborn'

    name = fields.Char('Newborn ID')
    patient = fields.Many2One('gnuhealth.patient',
                              'Baby',
                              required=True,
                              help="Patient associated to this newborn")

    mother = fields.Many2One('gnuhealth.patient', 'Mother')
    newborn_name = fields.Char('Name at Birth')
    birth_date = fields.DateTime('DoB',
                                 required=True,
                                 help="Date and Time of birth")
    photo = fields.Binary('Picture')
    newborn_sex = fields.Function(
        fields.Selection([
            ('m', 'Male'),
            ('f', 'Female'),
        ], 'Sex'), 'get_newborn_sex')

    # Sex / Gender at birth.

    sex = fields.Selection([
        ('m', 'Male'),
        ('f', 'Female'),
        ], 'Sex',sort=False, required=True,
            help="Sex at birth. It might differ from the current patient" \
            " sex")

    cephalic_perimeter = fields.Integer(
        'CP', help="Cephalic Perimeter in centimeters (cm)")
    length = fields.Integer('Length', help="Length in centimeters (cm)")
    weight = fields.Integer('Weight', help="Weight in grams (g)")
    apgar1 = fields.Integer('APGAR 1st minute')
    apgar5 = fields.Integer('APGAR 5th minute')
    apgar_scores = fields.One2Many('gnuhealth.neonatal.apgar', 'name',
                                   'APGAR scores')
    meconium = fields.Boolean('Meconium')
    congenital_diseases = fields.One2Many('gnuhealth.patient.disease',
                                          'newborn_id', 'Congenital diseases')
    reanimation_stimulation = fields.Boolean('Stimulation')
    reanimation_aspiration = fields.Boolean('Aspiration')
    reanimation_intubation = fields.Boolean('Intubation')
    reanimation_mask = fields.Boolean('Mask')
    reanimation_oxygen = fields.Boolean('Oxygen')
    test_vdrl = fields.Boolean('VDRL')
    test_toxo = fields.Boolean('Toxoplasmosis')
    test_chagas = fields.Boolean('Chagas')
    test_billirubin = fields.Boolean('Billirubin')
    test_audition = fields.Boolean('Audition')
    test_metabolic = fields.Boolean(
        'Metabolic ("heel stick screening")',
        help="Test for Fenilketonuria, Congenital Hypothyroidism, "
        "Quistic Fibrosis, Galactosemia")
    neonatal_ortolani = fields.Boolean('Positive Ortolani')
    neonatal_barlow = fields.Boolean('Positive Barlow')
    neonatal_hernia = fields.Boolean('Hernia')
    neonatal_ambiguous_genitalia = fields.Boolean('Ambiguous Genitalia')
    neonatal_erbs_palsy = fields.Boolean('Erbs Palsy')
    neonatal_hematoma = fields.Boolean('Hematomas')
    neonatal_talipes_equinovarus = fields.Boolean('Talipes Equinovarus')
    neonatal_polydactyly = fields.Boolean('Polydactyly')
    neonatal_syndactyly = fields.Boolean('Syndactyly')
    neonatal_moro_reflex = fields.Boolean('Moro Reflex')
    neonatal_grasp_reflex = fields.Boolean('Grasp Reflex')
    neonatal_stepping_reflex = fields.Boolean('Stepping Reflex')
    neonatal_babinski_reflex = fields.Boolean('Babinski Reflex')
    neonatal_blink_reflex = fields.Boolean('Blink Reflex')
    neonatal_sucking_reflex = fields.Boolean('Sucking Reflex')
    neonatal_swimming_reflex = fields.Boolean('Swimming Reflex')
    neonatal_tonic_neck_reflex = fields.Boolean('Tonic Neck Reflex')
    neonatal_rooting_reflex = fields.Boolean('Rooting Reflex')
    neonatal_palmar_crease = fields.Boolean('Transversal Palmar Crease')
    medication = fields.One2Many('gnuhealth.patient.medication', 'newborn_id',
                                 'Medication')
    responsible = fields.Many2One('gnuhealth.healthprofessional',
                                  'Doctor in charge',
                                  help="Signed by the health professional")
    dismissed = fields.DateTime('Discharged')
    bd = fields.Boolean('Stillbirth')
    died_at_delivery = fields.Boolean('Died at delivery room')
    died_at_the_hospital = fields.Boolean('Died at the hospital')
    died_being_transferred = fields.Boolean(
        'Died being transferred',
        help="The baby died being transferred to another health institution")
    tod = fields.DateTime('Time of Death')
    cod = fields.Many2One('gnuhealth.pathology', 'Cause of death')
    notes = fields.Text('Notes')

    @classmethod
    def __setup__(cls):
        super(Newborn, cls).__setup__()

        cls._sql_constraints = [
            ('name_uniq', 'unique(name)', 'The Newborn ID must be unique !'),
        ]

    def get_newborn_sex(self, name):
        if self.patient:
            return self.patient.sex
Example #30
0
class CrmCaseSection(ModelSQL, ModelView):
    _name = "ekd.crm.case.section"
    _description = "Case Section"

    name = fields.Char('Case Section',size=64, required=True, translate=True)
    code = fields.Char('Section Code',size=8)
    active = fields.Boolean('Active')
    allow_unlink = fields.Boolean('Allow Delete', help="Allows to delete non draft cases")
    sequence = fields.Integer('Sequence')
    user = fields.Many2One('res.user', 'Responsible User')
    reply_to = fields.Char('Reply-To', size=64, help="The email address put in the 'Reply-To' of all emails sent by Open ERP about cases in this section")
    parent = fields.Many2One('ekd.crm.case.section', 'Parent Section')
    child_ids = fields.One2Many('ekd.crm.case.section', 'parent', 'Child Sections')

    def __init__(self):
        super(CrmCaseSection, self).__init__()

        self._constraints += [
            ('_check_recursion', 'Error ! You cannot create recursive sections.')
        ]
        self._sql_constraints += [
            ('code_uniq', 'unique (code)', 'The code of the section must be unique !')
        ]

        self._error_messages.update({
            'recursive_accounts': 'You can not create recursive accounts!',
        })

        self._order.insert(0, ('code', 'ASC'))
        self._order.insert(1, ('name', 'ASC'))


    def default_active(self):
        return True

    def default_allow_unlink(self):
        return True

    def _check_recursion(self, ids):
        cr = Transaction().cursor
        level = 100
        while len(ids):
            cr.execute('SELECT DISTINCT parent FROM ekd_crm_case_section '\
                       'WHERE id IN %s',
                       (tuple(ids),))
            ids = filter(None, map(lambda x:x[0], cr.fetchall()))
            if not level:
                return False
            level -= 1
        return True

    # Mainly used by the wizard
    def menu_create_data(self, data, menu_lst):
        menus = {}
        menus[0] = data['menu_parent']
        section = self.browse(data['section'])
        for (index, mname, mdomain, latest, view_mode) in menu_lst:
            view_mode = data['menu'+str(index)+'_option']
            if view_mode=='no':
                menus[index] = data['menu_parent']
                continue
            icon = icon_lst.get(view_mode.split(',')[0], 'STOCK_JUSTIFY_FILL')
            menu_id=self.pool.get('ir.ui.menu').create( {
                'name': data['menu'+str(index)],
                'parent': menus[latest],
                'icon': icon
            })
            menus[index] = menu_id
            action_id = self.pool.get('ir.actions.act_window').create( {
                'name': data['menu'+str(index)],
                'res_model': 'ekd.crm.case',
                'domain': mdomain.replace('SECTION_ID', str(data['section'])),
                'view_type': 'form',
                'view_mode': view_mode,
            })
            seq = 0
            for mode in view_mode.split(','):
                self.pool.get('ir.actions.act_window.view').create( {
                    'sequence': seq,
                    'view_id': data['view_'+mode],
                    'view_mode': mode,
                    'act_window_id': action_id,
                    'multi': True
                })
                seq+=1
            self.pool.get('ir.values').create( {
                'name': data['menu'+str(index)],
                'key2': 'tree_but_open',
                'model': 'ir.ui.menu',
                'res_id': menu_id,
                'value': 'ir.actions.act_window,%d'%action_id,
                'object': True
            })
        return True

    #
    # Used when called from .XML file
    #
    def menu_create(self, ids, name, menu_parent_id=False):
        menus = {}
        menus[-1] = menu_parent_id
        for section in self.browse( ids):
            for (index, mname, mdomain, latest) in [
                (0,'',"[('section','=',"+str(section.id)+")]", -1),
                (1,'My ',"[('section','=',"+str(section.id)+"),('user','=',uid)]", 0),
                (2,'My Unclosed ',"[('section','=',"+str(section.id)+"),('user','=',uid), ('state','<>','cancel'), ('state','<>','done')]", 1),
                (5,'My Open ',"[('section','=',"+str(section.id)+"),('user','=',uid), ('state','=','open')]", 2),
                (6,'My Pending ',"[('section','=',"+str(section.id)+"),('user','=',uid), ('state','=','pending')]", 2),
                (7,'My Draft ',"[('section','=',"+str(section.id)+"),('user','=',uid), ('state','=','draft')]", 2),

                (3,'My Late ',"[('section','=',"+str(section.id)+"),('user','=',uid), ('date_deadline','<=',time.strftime('%Y-%m-%d')), ('state','<>','cancel'), ('state','<>','done')]", 1),
                (4,'My Canceled ',"[('section','=',"+str(section.id)+"),('user','=',uid), ('state','=','cancel')]", 1),
                (8,'All ',"[('section','=',"+str(section.id)+"),]", 0),
                (9,'Unassigned ',"[('section','=',"+str(section.id)+"),('user','=',False)]", 8),
                (10,'Late ',"[('section','=',"+str(section.id)+"),('user','=',uid), ('date_deadline','<=',time.strftime('%Y-%m-%d')), ('state','<>','cancel'), ('state','<>','done')]", 8),
                (11,'Canceled ',"[('section','=',"+str(section.id)+"),('state','=','cancel')]", 8),
                (12,'Unclosed ',"[('section','=',"+str(section.id)+"),('state','<>','cancel'), ('state','<>','done')]", 8),
                (13,'Open ',"[('section','=',"+str(section.id)+"),('state','=','open')]", 12),
                (14,'Pending ',"[('section','=',"+str(section.id)+"),('state','=','pending')]", 12),
                (15,'Draft ',"[('section','=',"+str(section.id)+"),('state','=','draft')]", 12),
                (16,'Unassigned ',"[('section','=',"+str(section.id)+"),('user','=',False),('state','<>','cancel'),('state','<>','done')]", 12),
            ]:
                view_mode = 'tree,form'
                icon = 'STOCK_JUSTIFY_FILL'
                if index==0:
                    view_mode = 'form,tree'
                    icon = 'STOCK_NEW'
                menu_id=self.pool.get('ir.ui.menu').create( {
                    'name': mname+name,
                    'parent_id': menus[latest],
                    'icon': icon
                })
                menus[index] = menu_id
                action_id = self.pool.get('ir.actions.act_window').create({
                    'name': mname+name+' Cases',
                    'res_model': 'ekd.crm.case',
                    'domain': mdomain,
                    'view_type': 'form',
                    'view_mode': view_mode,
                })
                self.pool.get('ir.values').create({
                    'name': 'Open Cases',
                    'key2': 'tree_but_open',
                    'model': 'ir.ui.menu',
                    'res_id': menu_id,
                    'value': 'ir.actions.act_window,%d'%action_id,
                    'object': True
                })
        return True

    def name_get(self, ids):
        if not len(ids):
            return []
        reads = self.read( ids, ['name','parent_id'])
        res = []
        for record in reads:
            name = record['name']
            if record['parent_id']:
                name = record['parent_id'][1]+' / '+name
            res.append((record['id'], name))
        return res