Пример #1
0
class ResultsReportVersionDetailSample(metaclass=PoolMeta):
    __name__ = 'lims.results_report.version.detail.sample'

    trend_charts = fields.Function(fields.Text('Trend Charts'),
                                   'get_trend_charts')
    attachments = fields.Function(fields.Text('Attachments'),
                                  'get_attachments')

    def get_trend_charts(self, name):
        pool = Pool()
        OpenTrendChart = pool.get('lims.trend.chart.open', type='wizard')
        ResultReport = pool.get('lims.result_report', type='report')

        if not self.version_detail.trend_charts:
            return ''

        charts = []
        for tc in self.version_detail.trend_charts:
            session_id, _, _ = OpenTrendChart.create()
            open_chart = OpenTrendChart(session_id)
            open_chart.start.chart = tc.chart
            open_chart.start.notebook = self.notebook
            open_chart.transition_compute()
            plot = tc.chart.get_plot(session_id)
            charts.append(plot)

        div_row = '<div style="clear:both;">'
        charts_x_row = int(self.version_detail.charts_x_row) or 1
        if charts_x_row == 1:
            div_col = '<div style="float:left; width:100%;">'
        elif charts_x_row == 2:
            div_col = '<div style="float:left; width:50%;">'
        end_div = '</div>'

        content = '<div>'
        count = 0
        for chart in charts:
            if count == 0:
                content += div_row

            content += div_col
            content += ('<img src="' + ResultReport.get_image(chart) +
                        '" alt="" style="width:100%;">')
            content += end_div

            count += 1
            if count == charts_x_row:
                content += end_div
                count = 0
        if count != 0:
            content += end_div

        content += end_div
        return content

    def get_trend_charts_odt(self):
        pool = Pool()
        OpenTrendChart = pool.get('lims.trend.chart.open', type='wizard')

        if not self.version_detail.trend_charts:
            return []

        charts = []
        for tc in self.version_detail.trend_charts:
            session_id, _, _ = OpenTrendChart.create()
            open_chart = OpenTrendChart(session_id)
            open_chart.start.chart = tc.chart
            open_chart.start.notebook = self.notebook
            open_chart.transition_compute()
            plot = tc.chart.get_plot(session_id)
            charts.append(plot)
        return charts

    def _get_resource(self, obj):
        return '%s,%s' % (obj.__name__, obj.id)

    def get_attachments(self, name):
        pool = Pool()
        Attachment = pool.get('ir.attachment')
        ResultReport = pool.get('lims.result_report', type='report')

        resources = []
        resources.append(self._get_resource(self))
        resources.append(self._get_resource(self.notebook))
        resources.append(self._get_resource(self.notebook.fraction))
        resources.append(self._get_resource(self.notebook.fraction.sample))
        resources.append(
            self._get_resource(self.notebook.fraction.sample.entry))
        for line in self.notebook_lines:
            resources.append(self._get_resource(line))
            resources.append(self._get_resource(line.notebook_line))

        attachments = Attachment.search([
            ('resource', 'in', resources),
        ])

        div_row = '<div>'
        div_col = '<div style="float:left; width:50%;">'
        end_div = '</div>'

        content = '<div>'
        count = 0
        extensions = ['png', 'jpg']
        for attachment in attachments:
            if not any(x in attachment.name.lower() for x in extensions):
                continue

            if count == 0:
                content += div_row

            content += div_col

            if attachment.title:
                content += '<p style="font-size: 6pt;font-family: arial,\
                    helvetica, sans-serif;">%s</p>' % (attachment.title, )

            content += ('<img src="' +
                        ResultReport.get_image(attachment.data) +
                        '" alt="" style="width:100%;">')
            content += end_div

            count += 1
            if count == 2:
                content += end_div
                count = 0
        if count != 0:
            content += end_div

        content += end_div
        return content
Пример #2
0
class notacreditoExito(ModelView):
    'notacredito Exito'
    __name__ = 'sigcoop_wizard_ventas.notacredito.exito'
    resumen = fields.Text('Resumen', readonly=True)
Пример #3
0
class Address(DeactivableMixin, sequence_ordered(), ModelSQL, ModelView):
    "Address"
    __name__ = 'party.address'
    party = fields.Many2One('party.party',
                            'Party',
                            required=True,
                            ondelete='CASCADE',
                            select=True,
                            states={
                                'readonly': Eval('id', 0) > 0,
                            },
                            depends=['id'])
    party_name = fields.Char(
        "Party Name",
        help="If filled, replace the name of the party for address formatting")
    name = fields.Char("Building Name")
    street = fields.Text("Street")
    postal_code = fields.Char("Postal Code")
    city = fields.Char("City")
    country = fields.Many2One('country.country', "Country")
    subdivision_types = fields.Function(
        fields.MultiSelection('get_subdivision_types', "Subdivision Types"),
        'on_change_with_subdivision_types')
    subdivision = fields.Many2One(
        "country.subdivision",
        'Subdivision',
        domain=[
            ('country', '=', Eval('country', -1)),
            If(Eval('subdivision_types', []),
               ('type', 'in', Eval('subdivision_types', [])), ()),
        ],
        depends=['country', 'subdivision_types'])
    full_address = fields.Function(fields.Text('Full Address'),
                                   'get_full_address')

    @classmethod
    def __setup__(cls):
        super(Address, cls).__setup__()
        cls._order.insert(0, ('party', 'ASC'))
        cls.__rpc__.update(
            autocomplete_postal_code=RPC(instantiate=0, cache=dict(days=1)),
            autocomplete_city=RPC(instantiate=0, cache=dict(days=1)),
        )

    @classmethod
    def __register__(cls, module_name):
        cursor = Transaction().connection.cursor()
        sql_table = cls.__table__()
        table = cls.__table_handler__(module_name)

        # Migration from 5.8: rename zip to postal code
        table.column_rename('zip', 'postal_code')

        super(Address, cls).__register__(module_name)

        table = cls.__table_handler__(module_name)

        # Migration from 4.0: remove streetbis
        if table.column_exist('streetbis'):
            value = Concat(Coalesce(sql_table.street, ''),
                           Concat('\n', Coalesce(sql_table.streetbis, '')))
            cursor.execute(*sql_table.update([sql_table.street], [value]))
            table.drop_column('streetbis')

    _autocomplete_limit = 100

    @fields.depends('country', 'subdivision')
    def _autocomplete_domain(self):
        domain = []
        if self.country:
            domain.append(('country', '=', self.country.id))
        if self.subdivision:
            domain.append([
                'OR',
                ('subdivision', 'child_of', [self.subdivision.id], 'parent'),
                ('subdivision', '=', None),
            ])
        return domain

    def _autocomplete_search(self, domain, name):
        pool = Pool()
        PostalCode = pool.get('country.postal_code')
        if domain:
            records = PostalCode.search(domain, limit=self._autocomplete_limit)
            if len(records) < self._autocomplete_limit:
                return sorted({getattr(z, name) for z in records})
        return []

    @fields.depends('city', methods=['_autocomplete_domain'])
    def autocomplete_postal_code(self):
        domain = self._autocomplete_domain()
        if self.city:
            domain.append(('city', 'ilike', '%%%s%%' % self.city))
        return self._autocomplete_search(domain, 'postal_code')

    @fields.depends('postal_code', methods=['_autocomplete_domain'])
    def autocomplete_city(self):
        domain = self._autocomplete_domain()
        if self.postal_code:
            domain.append(('postal_code', 'ilike', '%s%%' % self.postal_code))
        return self._autocomplete_search(domain, 'city')

    def get_full_address(self, name):
        pool = Pool()
        AddressFormat = pool.get('party.address.format')
        full_address = Template(AddressFormat.get_format(self)).substitute(
            **self._get_address_substitutions())
        return '\n'.join(
            filter(None, (x.strip() for x in full_address.splitlines())))

    def _get_address_substitutions(self):
        context = Transaction().context
        subdivision_code = ''
        if getattr(self, 'subdivision', None):
            subdivision_code = self.subdivision.code or ''
            if '-' in subdivision_code:
                subdivision_code = subdivision_code.split('-', 1)[1]
        substitutions = {
            'party_name':
            '',
            'attn':
            '',
            'name':
            getattr(self, 'name', None) or '',
            'street':
            getattr(self, 'street', None) or '',
            'postal_code':
            getattr(self, 'postal_code', None) or '',
            'city':
            getattr(self, 'city', None) or '',
            'subdivision': (self.subdivision.name if getattr(
                self, 'subdivision', None) else ''),
            'subdivision_code':
            subdivision_code,
            'country':
            (self.country.name if getattr(self, 'country', None) else ''),
            'country_code': (self.country.code or '' if getattr(
                self, 'country', None) else ''),
        }
        # Keep zip for backward compatibility
        substitutions['zip'] = substitutions['postal_code']
        if context.get('address_from_country') == getattr(self, 'country', ''):
            substitutions['country'] = ''
        if context.get('address_with_party', False):
            substitutions['party_name'] = self.party_full_name
        if context.get('address_attention_party', False):
            substitutions['attn'] = (
                context['address_attention_party'].full_name)
        for key, value in list(substitutions.items()):
            substitutions[key.upper()] = value.upper()
        return substitutions

    @property
    def party_full_name(self):
        name = ''
        if self.party_name:
            name = self.party_name
        elif self.party:
            name = self.party.full_name
        return name

    def get_rec_name(self, name):
        party = self.party_full_name
        if self.street:
            street = self.street.splitlines()[0]
        else:
            street = None
        if self.country:
            country = self.country.code
        else:
            country = None
        return ', '.join(
            filter(None, [
                party, self.name, street, self.postal_code, self.city, country
            ]))

    @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,
            ('party', ) + tuple(clause[1:]),
            ('name', ) + tuple(clause[1:]),
            ('street', ) + tuple(clause[1:]),
            ('postal_code', ) + tuple(clause[1:]),
            ('city', ) + tuple(clause[1:]),
            ('country', ) + tuple(clause[1:]),
        ]

    @classmethod
    def write(cls, *args):
        actions = iter(args)
        for addresses, values in zip(actions, actions):
            if 'party' in values:
                for address in addresses:
                    if address.party.id != values['party']:
                        raise AccessError(
                            gettext('party.msg_address_change_party',
                                    address=address.rec_name))
        super(Address, cls).write(*args)

    @fields.depends('subdivision', 'country')
    def on_change_country(self):
        if (self.subdivision and self.subdivision.country != self.country):
            self.subdivision = None

    @classmethod
    def get_subdivision_types(cls):
        pool = Pool()
        Subdivision = pool.get('country.subdivision')
        return Subdivision.fields_get(['type'])['type']['selection']

    @fields.depends('country')
    def on_change_with_subdivision_types(self, name=None):
        pool = Pool()
        Types = pool.get('party.address.subdivision_type')
        return Types.get_types(self.country)
Пример #4
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
Пример #5
0
class Message(Workflow, ModelSQL, ModelView):
    'SEPA Message'
    __name__ = 'account.payment.sepa.message'
    _states = {
        'readonly': Eval('state') != 'draft',
        }
    _depends = ['state']
    message = fields.Text('Message', states=_states, depends=_depends)
    filename = fields.Function(fields.Char('Filename'), 'get_filename')
    type = fields.Selection([
            ('in', 'IN'),
            ('out', 'OUT'),
            ], 'Type', required=True, states=_states, depends=_depends)
    company = fields.Many2One('company.company', 'Company', required=True,
        select=True,
        domain=[
            ('id', If(Eval('context', {}).contains('company'), '=', '!='),
                Eval('context', {}).get('company', -1)),
            ],
        states={
            'readonly': Eval('state') != 'draft',
            },
        depends=['state'])
    origin = fields.Reference('Origin', selection='get_origin', select=True,
        states=_states, depends=_depends)
    state = fields.Selection([
            ('draft', 'Draft'),
            ('waiting', 'Waiting'),
            ('done', 'Done'),
            ('canceled', 'Canceled'),
            ], 'State', readonly=True, select=True)

    @classmethod
    def __setup__(cls):
        super(Message, cls).__setup__()
        cls._transitions |= {
            ('draft', 'waiting'),
            ('waiting', 'done'),
            ('waiting', 'draft'),
            ('draft', 'canceled'),
            ('waiting', 'canceled'),
            }
        cls._buttons.update({
                'cancel': {
                    'invisible': ~Eval('state').in_(['draft', 'waiting']),
                    },
                'draft': {
                    'invisible': Eval('state') != 'waiting',
                    },
                'wait': {
                    'invisible': Eval('state') != 'draft',
                    },
                'do': {
                    'invisible': Eval('state') != 'waiting',
                    },
                })

    @classmethod
    def __register__(cls, module_name):
        TableHandler = backend.get('TableHandler')
        cursor = Transaction().connection.cursor()
        pool = Pool()
        Group = pool.get('account.payment.group')

        super(Message, cls).__register__(module_name)

        # Migration from 3.2
        if TableHandler.table_exist(Group._table):
            group_table = TableHandler(Group, module_name)
            if group_table.column_exist('sepa_message'):
                group = Group.__table__()
                table = cls.__table__()
                cursor.execute(*group.select(
                        group.id, group.sepa_message, group.company))
                for group_id, message, company_id in cursor.fetchall():
                    cursor.execute(*table.insert(
                            [table.message, table.type, table.company,
                                table.origin, table.state],
                            [[message, 'out', company_id,
                                    'account.payment.group,%s' % group_id,
                                    'done']]))
                group_table.drop_column('sepa_message')

    @staticmethod
    def default_type():
        return 'in'

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

    @staticmethod
    def default_state():
        return 'draft'

    def get_filename(self, name):
        pool = Pool()
        Group = pool.get('account.payment.group')
        if isinstance(self.origin, Group):
            return self.origin.rec_name + '.xml'

    @staticmethod
    def _get_origin():
        'Return list of Model names for origin Reference'
        return ['account.payment.group']

    @classmethod
    def get_origin(cls):
        IrModel = Pool().get('ir.model')
        models = cls._get_origin()
        models = IrModel.search([
                ('model', 'in', models),
                ])
        return [(None, '')] + [(m.model, m.name) for m in models]

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

    @classmethod
    @ModelView.button
    @Workflow.transition('waiting')
    def wait(cls, messages):
        pass

    @classmethod
    @ModelView.button
    @Workflow.transition('done')
    def do(cls, messages):
        for message in messages:
            if message.type == 'in':
                message.parse()
            else:
                message.send()

    @classmethod
    @ModelView.button
    @Workflow.transition('canceled')
    def cancel(cls, messages):
        pass

    @staticmethod
    def _get_handlers():
        pool = Pool()
        Payment = pool.get('account.payment')
        return {
            'urn:iso:std:iso:20022:tech:xsd:camt.054.001.01':
            lambda f: CAMT054(f, Payment),
            'urn:iso:std:iso:20022:tech:xsd:camt.054.001.02':
            lambda f: CAMT054(f, Payment),
            'urn:iso:std:iso:20022:tech:xsd:camt.054.001.03':
            lambda f: CAMT054(f, Payment),
            'urn:iso:std:iso:20022:tech:xsd:camt.054.001.04':
            lambda f: CAMT054(f, Payment),
            }

    @staticmethod
    def get_namespace(message):
        f = BytesIO(message)
        for _, element in etree.iterparse(f, events=('start',)):
            tag = etree.QName(element)
            if tag.localname == 'Document':
                return tag.namespace

    def parse(self):
        message = self.message.encode('utf-8')
        f = BytesIO(message)
        namespace = self.get_namespace(message)
        handlers = self._get_handlers()
        if namespace not in handlers:
            raise  # TODO UserError
        handlers[namespace](f)

    def send(self):
        pass
Пример #6
0
class AddressFormat(DeactivableMixin, MatchMixin, ModelSQL, ModelView):
    "Address Format"
    __name__ = 'party.address.format'
    country = fields.Many2One('country.country', "Country")
    language = fields.Many2One('ir.lang', "Language")
    format_ = fields.Text("Format",
                          required=True,
                          help="Available variables (also in upper case):\n"
                          "- ${party_name}\n"
                          "- ${name}\n"
                          "- ${attn}\n"
                          "- ${street}\n"
                          "- ${zip}\n"
                          "- ${city}\n"
                          "- ${subdivision}\n"
                          "- ${subdivision_code}\n"
                          "- ${country}\n"
                          "- ${country_code}")

    _get_format_cache = Cache('party.address.format.get_format')

    @classmethod
    def __setup__(cls):
        super(AddressFormat, cls).__setup__()
        cls._order.insert(0, ('country', 'ASC'))
        cls._order.insert(1, ('language', 'ASC'))

    @classmethod
    def default_format_(cls):
        return """${party_name}
${name}
${street}
${zip} ${city}
${subdivision}
${COUNTRY}"""

    @staticmethod
    def order_language(tables):
        table, _ = tables[None]
        return [Case((table.language == Null, 1), else_=0), table.language]

    @classmethod
    def create(cls, *args, **kwargs):
        records = super(AddressFormat, cls).create(*args, **kwargs)
        cls._get_format_cache.clear()
        return records

    @classmethod
    def write(cls, *args, **kwargs):
        super(AddressFormat, cls).write(*args, **kwargs)
        cls._get_format_cache.clear()

    @classmethod
    def delete(cls, *args, **kwargs):
        super(AddressFormat, cls).delete(*args, **kwargs)
        cls._get_format_cache.clear()

    @classmethod
    def validate(cls, formats):
        super(AddressFormat, cls).validate(formats)
        for format_ in formats:
            format_.check_format()

    def check_format(self):
        pool = Pool()
        Address = pool.get('party.address')
        address = Address()
        try:
            Template(self.format_).substitute(
                **address._get_address_substitutions())
        except Exception as exception:
            raise InvalidFormat(
                gettext('party.invalid_format',
                        format=self.format_,
                        exception=exception)) from exception

    @classmethod
    def get_format(cls, address, pattern=None):
        pool = Pool()
        Language = pool.get('ir.lang')

        if pattern is None:
            pattern = {}
        else:
            pattern = pattern.copy()
        pattern.setdefault('country',
                           address.country.id if address.country else None)

        languages = Language.search([
            ('code', '=', Transaction().language),
        ],
                                    limit=1)
        if languages:
            language, = languages
        else:
            language = None
        pattern.setdefault('language', language.id if language else None)

        key = tuple(sorted(pattern.items()))
        format_ = cls._get_format_cache.get(key)
        if format_ is not None:
            return format_

        for record in cls.search([]):
            if record.match(pattern):
                format_ = record.format_
                break
        else:
            format_ = cls.default_format_()

        cls._get_format_cache.set(key, format_)
        return format_
Пример #7
0
class TransportRequest(ModelSQL, ModelView):
    'Transport Request Registration'
    __name__ = 'policoop.transport_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')

    request_date = fields.DateTime('Date', required=True,
        help="Date and time of the call for help")

    return_date = fields.DateTime('Return_date', required=True,
        help="Date and time of return")
    
    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")
   
    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'),
        ('urbanzone', 'Urban Zone'),
        ('ruralzone', 'Rural zone'),
        ], 'Origin', help="Place of occurrance",sort=False)

    event_type = fields.Selection([
        (None, ''),
        ('event1', 'Zonal'),
        ('event2', 'Urbano'),
        ], 'Event type')

    service_type = fields.Selection([
        (None, ''),
        ('event1', 'Alta'),
        ('event2', 'Internación'),
        ], 'Tipo de Servicio')

    escort = fields.Text("Acompañante", help="Persona que acompaña al afectado en la ambulancia / Descripción o relación")

    wait = fields.Selection([
        (None, ''),
        ('event1', 'Si'),
        ('event2', 'No'),
        ], '¿Con espera?', help="¿La ambulancia se queda esperando en el lugar?")

    ambulances = fields.One2Many(
        'policoop.ambulance.transport', '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)

    lines = fields.One2Many(
        'policoop.transport.line', 'inventory', 'Lines')
 
    @staticmethod
    def default_request_date():
        return datetime.now()

    @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('policoop.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.transport_request_code_sequence.id)

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


    @classmethod
    def __setup__(cls):
        super(TransportRequest, 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'})
Пример #8
0
class Iss(ModelSQL, ModelView):
    'Injury Surveillance System Registration'
    __name__ = 'gnuhealth.iss'

    name = fields.Many2One('gnuhealth.patient.evaluation',
                           'Evaluation',
                           required=True,
                           help='Related Patient Evaluation')

    injury_date = fields.Date('Injury Date',
                              help="Usually the same as the Evaluation")

    registration_date = fields.Date('Registration Date')

    code = fields.Char('Code', help='Injury Code', required=True)

    operational_sector = fields.Many2One(
        'gnuhealth.operational_sector',
        'O. Sector',
        help="Operational Sector in which happened the injury")

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

    urladdr = fields.Char(
        'OSM Map',
        help="Maps the Accident / Injury location on Open Street Map")

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

    patient = fields.Function(fields.Char('Patient'),
                              'get_patient',
                              searcher='search_patient')

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

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

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

    injury_type = fields.Selection([
        (None, ''),
        ('accidental', 'Accidental / Unintentional'),
        ('violence', 'Violence'),
        ('attempt_suicide', 'Suicide Attempt'),
        ('motor_vehicle', 'Motor Vehicle'),
    ],
                                   'Injury Type',
                                   required=True,
                                   sort=False)

    mva_mode = fields.Selection(
        [
            (None, ''),
            ('pedestrian', 'Pedestrian'),
            ('bicycle', 'Bicycle'),
            ('motorbike', 'Motorbike'),
            ('car', 'Car'),
            ('van', 'Van / Pickup / Jeep'),
            ('truck', 'Truck / Heavy vehicle'),
            ('bus', 'Bus'),
            ('train', 'Train'),
            ('taxi', 'Taxi'),
            ('boat', 'Boat / Ship'),
            ('aircraft', 'Aircraft'),
            ('other', 'Other'),
            ('unknown', 'Unknown'),
        ],
        'Mode',
        help="Motor Vehicle Accident Mode",
        sort=False,
        states={'required': Equal(Eval('injury_type'), 'motor_vehicle')})

    mva_position = fields.Selection(
        [
            (None, ''),
            ('driver', 'Driver'),
            ('passenger', 'Passenger'),
            ('outside', 'Outside / on the back'),
            ('bystander', 'Bystander'),
            ('unspecified_vehicle', 'Unspecified vehicle'),
            ('unknown', 'Unknown'),
        ],
        'User Position',
        help="Motor Vehicle Accident user position",
        sort=False,
        states={'required': Equal(Eval('injury_type'), 'motor_vehicle')})

    mva_counterpart = fields.Selection(
        [
            (None, ''),
            ('pedestrian', 'Pedestrian'),
            ('bicycle', 'Bicycle'),
            ('motorbike', 'Motorbike'),
            ('car', 'Car'),
            ('van', 'Van / Pickup / Jeep'),
            ('truck', 'Truck / Heavy vehicle'),
            ('bus', 'Bus'),
            ('train', 'Train'),
            ('taxi', 'Taxi'),
            ('boat', 'Boat / Ship'),
            ('aircraft', 'Aircraft'),
            ('other', 'Other'),
            ('unknown', 'Unknown'),
        ],
        'Counterpart',
        help="Motor Vehicle Accident Counterpart",
        sort=False,
        states={'required': Equal(Eval('injury_type'), 'motor_vehicle')})

    safety_gear = fields.Selection(
        [
            (None, ''),
            ('yes', 'Yes'),
            ('no', 'No'),
            ('unknown', 'Unknown'),
        ],
        'Safety Gear',
        help="Use of Safety Gear - Helmet, safety belt...",
        sort=False,
        states={'required': Equal(Eval('injury_type'), 'motor_vehicle')})

    alcohol = fields.Selection(
        [
            (None, ''),
            ('yes', 'Yes'),
            ('no', 'No'),
            ('suspected', 'Suspected'),
            ('unknown', 'Unknown'),
        ],
        'Alcohol',
        required=True,
        help="Is there evidence of alcohol use by the injured person"
        " in the 6 hours before the accident ?",
        sort=False)

    drugs = fields.Selection(
        [
            (None, ''),
            ('yes', 'Yes'),
            ('no', 'No'),
            ('suspected', 'Suspected'),
            ('unknown', 'Unknown'),
        ],
        'Other Drugs',
        required=True,
        help="Is there evidence of drug use by the injured person"
        " in the 6 hours before the accident ?",
        sort=False)

    injury_details = fields.Text('Details')

    # Add victim-perpretator relationship for violence-related injuries
    victim_perpetrator = fields.Selection(
        [
            (None, ''),
            ('parent', 'Parent'),
            ('spouse', 'Wife / Husband'),
            ('girlboyfriend', 'Girl / Boyfriend'),
            ('relative', 'Other relative'),
            ('acquaintance', 'Acquaintance / Friend'),
            ('official', 'Official / Legal'),
            ('stranger', 'Stranger'),
            ('other', 'other'),
        ],
        'Relationship',
        help="Victim - Perpetrator relationship",
        sort=False,
        states={'required': Equal(Eval('injury_type'), 'violence')})

    violence_circumstances = fields.Selection(
        [
            (None, ''),
            ('fight', 'Fight'),
            ('robbery', 'Robbery'),
            ('drug', 'Drug Related'),
            ('sexual', 'Sexual Assault'),
            ('gang', 'Gang Activity'),
            ('other_crime', 'Committing a crime (other)'),
            ('other', 'Other'),
            ('unknown', 'Unknown'),
        ],
        'Context',
        help="Precipitating Factor",
        sort=False,
        states={'required': Equal(Eval('injury_type'), 'violence')})

    injury_method = fields.Selection(
        [
            (None, ''),
            ('blunt', 'Blunt object'),
            ('push', 'Push/bodily force'),
            ('sharp', 'Sharp objects'),
            ('gun', 'Gun shot'),
            ('sexual', 'Sexual Assault'),
            ('choking', 'Choking/strangulation'),
            ('other', 'Other'),
            ('unknown', 'Unknown'),
        ],
        'Method',
        help="Method of Injury",
        sort=False,
        states={'required': Equal(Eval('injury_type'), 'violence')})

    # Place of occurrance . Not used in motor vehicle accidents

    place_occurrance = fields.Selection(
        [
            (None, ''),
            ('home', 'Home'),
            ('street', 'Street'),
            ('institution', 'Institution'),
            ('school', 'School'),
            ('commerce', 'Commercial Area'),
            ('publicbuilding', 'Public Building'),
            ('recreational', 'Recreational Area'),
            ('transportation', 'Public transportation'),
            ('sports', 'Sports event'),
            ('unknown', 'Unknown'),
        ],
        'Place',
        help="Place of occurrance",
        sort=False,
        states={'required': Not(Equal(Eval('injury_type'), 'motor_vehicle'))})

    disposition = fields.Selection([
        (None, ''),
        ('treated_sent', 'Treated and Sent Home'),
        ('admitted', 'Admitted to Ward'),
        ('observation', 'Admitted to Observation'),
        ('died', 'Died'),
        ('daa', 'Discharge Against Advise'),
        ('transferred', 'Transferred'),
        ('doa', 'Dead on Arrival'),
    ],
                                   'Disposition',
                                   help="Place of occurrance",
                                   sort=False,
                                   required=True)

    def get_patient(self, name):
        return self.name.patient.rec_name

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

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

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

    @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 search_patient(cls, name, clause):
        res = []
        value = clause[2]
        res.append(('name.patient', clause[1], value))
        return res

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

    @classmethod
    def view_attributes(cls):
        return [
            ('//group[@id="motor_vehicle_accident"]', 'states', {
                'invisible': Not(Equal(Eval('injury_type'), 'motor_vehicle')),
            }),
            ('//group[@id="violent_injury"]', 'states', {
                'invisible': Not(Equal(Eval('injury_type'), 'violence')),
            }),
            ('//group[@id="iss_place"]', 'states', {
                'invisible': Equal(Eval('injury_type'), 'motor_vehicle'),
            }),
        ]
Пример #9
0
class QuotationLine(ModelSQL, ModelView):
    "Purchase Request For Quotation Line"
    __name__ = 'purchase.request.quotation.line'

    supplier = fields.Function(fields.Many2One('party.party', 'Supplier'),
                               'get_supplier')
    supply_date = fields.Date('Supply Date',
                              help="When it should be delivered.")
    product = fields.Function(fields.Many2One('product.product', 'Product'),
                              'get_product',
                              searcher='search_product')
    description = fields.Text('Description',
                              states={'required': ~Eval('product')})
    quantity = fields.Float("Quantity", digits='unit', required=True)
    unit = fields.Many2One(
        'product.uom',
        'Unit',
        ondelete='RESTRICT',
        states={
            'required': Bool(Eval('product')),
        },
        domain=[
            If(Bool(Eval('product_uom_category')),
               ('category', '=', Eval('product_uom_category')),
               ('category', '!=', -1)),
        ])
    product_uom_category = fields.Function(
        fields.Many2One('product.uom.category', 'Product Uom Category'),
        'on_change_with_product_uom_category')
    unit_price = Monetary("Unit Price",
                          currency='currency',
                          digits=price_digits)
    currency = fields.Many2One('currency.currency',
                               'Currency',
                               states={
                                   'required': Bool(Eval('unit_price')),
                               })
    request = fields.Many2One(
        'purchase.request',
        'Request',
        ondelete='CASCADE',
        select=True,
        required=True,
        domain=[
            If(
                Eval('quotation_state') == 'draft',
                ('state', 'in', ['draft', 'quotation', 'received']),
                (),
            ),
        ],
        states={'readonly': Eval('quotation_state') != 'draft'},
        help="The request which this line belongs to.")
    quotation = fields.Many2One('purchase.request.quotation',
                                'Quotation',
                                ondelete='CASCADE',
                                required=True,
                                domain=[
                                    ('supplier', '=', Eval('supplier')),
                                ])
    quotation_state = fields.Function(fields.Selection('get_quotation_state',
                                                       'Quotation State'),
                                      'on_change_with_quotation_state',
                                      searcher='search_quotation_state')

    @classmethod
    def __setup__(cls):
        super().__setup__()
        cls.__access__.add('quotation')

    @staticmethod
    def order_quotation_state(tables):
        pool = Pool()
        Quotation = pool.get('purchase.request.quotation')
        quotation_line, _ = tables[None]
        quotation = Quotation.__table__()
        tables['purchase.request.quotation'] = {
            None: (quotation, quotation_line.quotation == quotation.id),
        }
        return [
            Case((quotation.state == 'received', 0), else_=1), quotation.state
        ]

    def get_supplier(self, name):
        if self.quotation and self.quotation.supplier:
            return self.quotation.supplier.id

    @fields.depends('request', '_parent_request.product',
                    '_parent_request.description', '_parent_request.quantity',
                    '_parent_request.uom', '_parent_request.company',
                    '_parent_request.supply_date')
    def on_change_request(self):
        if self.request:
            self.product = self.request.product
            self.description = self.request.description
            self.quantity = self.request.quantity
            self.unit = self.request.uom
            if self.request.company:
                self.currency = self.request.company.currency
            self.supply_date = self.request.supply_date or datetime.date.max

    @fields.depends('product')
    def on_change_with_product_uom_category(self, name=None):
        if self.product:
            return self.product.default_uom_category.id

    @classmethod
    def get_quotation_state(cls):
        pool = Pool()
        Quotation = pool.get('purchase.request.quotation')
        return (Quotation.fields_get(['state'])['state']['selection'])

    @fields.depends('quotation', '_parent_quotation.state')
    def on_change_with_quotation_state(self, name=None):
        pool = Pool()
        Quotation = pool.get('purchase.request.quotation')
        if self.quotation:
            return self.quotation.state
        return Quotation.default_state()

    @classmethod
    def search_quotation_state(cls, name, clause):
        return [('quotation.state', ) + tuple(clause[1:])]

    def get_rec_name(self, name):
        return '%s - %s' % (self.quotation.rec_name, self.supplier.rec_name)

    @classmethod
    def search_rec_name(cls, name, clause):
        names = clause[2].split(' - ', 1)
        res = [('quotation', clause[1], names[0])]
        if len(names) != 1 and names[1]:
            res.append(('supplier', clause[1], names[1]))
        return res

    @classmethod
    def delete(cls, quotationlines):
        pool = Pool()
        Request = pool.get('purchase.request')
        requests = [l.request for l in quotationlines]
        super(QuotationLine, cls).delete(quotationlines)
        Request.update_state(requests)

    def get_product(self, name):
        if self.request and self.request.product:
            return self.request.product.id

    @classmethod
    def search_product(cls, name, clause):
        return [('request.' + clause[0], ) + tuple(clause[1:])]
Пример #10
0
class CrmCaseRule(ModelSQL, ModelView):
    _name = "ekd.crm.case.rule"
    _description = "Case Rule"

    name = fields.Char('Rule Name',size=64, required=True)
    active = fields.Boolean('Active')
    sequence = fields.Integer('Sequence')

    trg_state_from = fields.Selection([('',''),('escalate','Escalate')]+AVAILABLE_STATES, 'Case State')
    trg_state_to = fields.Selection([('',''),('escalate','Escalate')]+AVAILABLE_STATES, 'Button Pressed')

    trg_date_type = fields.Selection([
            ('none','None'),
            ('create','Creation Date'),
            ('action_last','Last Action Date'),
            ('deadline','Deadline'),
            ('date','Date'),
            ], 'Trigger Date')
    trg_date_range = fields.Integer('Delay after trigger date')
    trg_date_range_type = fields.Selection([('minutes', 'Minutes'),('hour','Hours'),('day','Days'),('month','Months')], 'Delay type')

    trg_section = fields.Many2One('ekd.crm.case.section', 'Section')
    trg_categ = fields.Many2One('ekd.crm.case.category', 'Category', domain=[('section','=',Eval('trg_section'))])
    trg_user = fields.Many2One('res.user', 'Responsible')

    trg_party = fields.Many2One('party.party', 'party')
    trg_party_categ = fields.Many2One('party.category', 'party Category')

    trg_priority_from = fields.Selection([('','')] + AVAILABLE_PRIORITIES, 'Minimum Priority')
    trg_priority_to = fields.Selection([('','')] + AVAILABLE_PRIORITIES, 'Maximim Priority')
    trg_max_history = fields.Integer('Maximum Communication History')

    act_method = fields.Char('Call Object Method', size=64)
    act_state = fields.Selection([('','')]+AVAILABLE_STATES, 'Set state to')
    act_section = fields.Many2One('ekd.crm.case.section', 'Set section to')
    act_user = fields.Many2One('res.user', 'Set responsible to')
    act_priority = fields.Selection([('','')] + AVAILABLE_PRIORITIES, 'Set priority to')
    act_email_cc = fields.Char('Add watchers (Cc)', size=250, help="These people will receive a copy of the futur communication between party and users by email")

    act_remind_party = fields.Boolean('Remind party', help="Check this if you want the rule to send a reminder by email to the party.")
    act_remind_user = fields.Boolean('Remind responsible', help="Check this if you want the rule to send a reminder by email to the user.")
    act_remind_attach = fields.Boolean('Remind with attachment', help="Check this if you want that all documents attached to the case be attached to the reminder email sent.")

    act_mail_to_user = fields.Boolean('Mail to responsible'),
    act_mail_to_party = fields.Boolean('Mail to party'),
    act_mail_to_watchers = fields.Boolean('Mail to watchers (Cc)'),
    act_mail_to_email = fields.Char('Mail to these emails', size=128),
    act_mail_body = fields.Text('Mail body')

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

        self._constraints += [
            ('_check_mail', 'Error: The mail is not well formated'),
        ]

        #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, ('sequence', 'ASC'))

    def default_active(self):
        return True

    def default_trg_date_type(self):
        return 'none'

    def default_trg_date_range_type(self):
        return 'day'

    def default_act_mail_to_user(self):
        return 0

    def default_act_remind_party(self):
        return 0

    def default_act_remind_user(self):
        return 0

    def default_act_mail_to_party(self):
        return 0

    def default_act_mail_to_watchers(self):
        return 0


    def _check(self, ids=False):
        '''
        Function called by the scheduler to process cases for date actions
        Only works on not done and cancelled cases
        '''
        cr.execute('select * from ekd_crm_case \
                where (date_action_last<%s or date_action_last is null) \
                and (date_action_next<=%s or date_action_next is null) \
                and state not in (\'cancel\',\'done\')',
                (time.strftime("%Y-%m-%d %H:%M:%S"),
                    time.strftime('%Y-%m-%d %H:%M:%S')))
        ids2 = map(lambda x: x[0], cr.fetchall() or [])
        case_obj = self.pool.get('ekd.crm.case')
        cases = case_obj.browse( ids2)
        return case_obj._action( cases, False, context=context)

    def _check_mail(self, ids):
        caseobj = self.pool.get('ekd.crm.case')
        emptycase = orm.browse_null()
        for rule in self.browse( ids):
            if rule.act_mail_body:
                try:
                    caseobj.format_mail(emptycase, rule.act_mail_body)
                except (ValueError, KeyError, TypeError):
                    return False
        return True
Пример #11
0
class CrmCase(ModelSQL, ModelView):
    _name = "ekd.crm.case"
    _description = "Case"

    id = fields.Integer('ID', readonly=True)
    name = fields.Char('Description',size=64,required=True)
    priority = fields.Selection(AVAILABLE_PRIORITIES, 'Priority')
    active = fields.Boolean('Active')
    description = fields.Text('Your action')
    section = fields.Many2One('ekd.crm.case.section', 'Section', required=True, select=True)
    category = fields.Many2One('ekd.crm.case.category', 'Category', 
                on_change=['category'], required=True,
                domain=[('section','=',Eval('section'))])
    planned_revenue = fields.Float('Planned Revenue')
    planned_cost = fields.Float('Planned Costs')
    probability = fields.Float('Probability (%)')
    email_from = fields.Char('party Email', size=128)
    email_cc = fields.Char('Watchers Emails', size=252)
    email_last = fields.Function(fields.Text('Latest E-Mail'), '_email_last')
    party = fields.Many2One('party.party', 'Party')
    party_address = fields.Many2One('party.address', 'Party Contact', domain=[('party','=',Eval('party'))])
    som = fields.Many2One('ekd.party.som', 'State of Mind')
    date = fields.DateTime('Date')
    create_date = fields.DateTime('Created' ,readonly=True)
    date_deadline = fields.DateTime('Deadline')
    date_closed = fields.DateTime('Closed', readonly=True)
    channel = fields.Many2One('ekd.party.channel', 'Channel')
    user = fields.Many2One('res.user', 'Responsible')
    history_line = fields.One2Many('ekd.crm.case.history', 'case', 'Communication', readonly=1)
    log_ids = fields.One2Many('ekd.crm.case.log', 'case', 'Logs History', readonly=1)
    state = fields.Selection(AVAILABLE_STATES, 'State', readonly=True)
    ref = fields.Reference('Reference', '_links_get')
    ref2 = fields.Reference('Reference 2', '_links_get')

    date_action_last = fields.DateTime('Last Action', readonly=1)
    date_action_next = fields.DateTime('Next Action', readonly=1)

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

        self._rpc.update({
            'button_case_log': True,
            'button_add_reply': True,
            'button_case_log_reply': True,
            'button_case_close': True,
            'button_case_open': True,
            'button_case_pending': True,
            'button_case_escalate': True,
            'button_case_reset': True,
            'button_case_cancel': True,
            'button_remind_party': True,
            'button_remind_user': True,
            })

        self._order.insert(0, ('priority', 'ASC'))
        self._order.insert(1, ('date_deadline', 'DESC'))
        self._order.insert(2, ('date', 'DESC'))
        self._order.insert(3, ('id', 'DESC'))

    def _email_last(self, ids, name, arg):
        res = {}
        for case in self.browse(ids):
            if case.history_line:
                res[case.id] = case.history_line[0].description
            else:
                res[case.id] = False
        return res

    def copy(self, id, default=None):
        if not default: default = {}
        default.update( {'state':'draft', 'id':False, 'history_line':[],'log_ids':[]})
        return super(crm_case, self).copy( id, default)

    def default_active(self):
        return True

#    def default_user(self):
#        return Transaction().user

#    def default_party(self):
#        user = self.pool.get('res.user').browse(Transaction().user)
#        if not user.address:
#            return False
#        return user.address.party.id

#    def default_party_address(self):
#        return self.pool.get('res.user').browse(Transaction().user).address.id

#    def default_email_from(self):
#        context = Transaction().context
#        if not context.get('portal',False):
#            return False
#        user = self.pool.get('res.user').browse(Transaction().user)
#        if not user.address:
#            return False
#        raise Exception(Transaction().user)
#        return user.address.email

    def default_state(self):
        return 'draft'

    def default_priority(self):
        return AVAILABLE_PRIORITIES[2][0],

    def default_date(self):
        return datetime.datetime.now()

    def _links_get(self):
        request_link_obj = self.pool.get('res.request.link')
        ids = request_link_obj.search([])
        request_links = request_link_obj.browse(ids)
        if request_links:
            return [(x.model, x.name) for x in request_links]

    def unlink(self, ids):
        for case in self.browse( ids):
            if (not case.section.allow_unlink) and (case.state <> 'draft'):
                self.raise_user_error('Warning !',
                    'You can not delete this case. You should better cancel it.')
        return super(crm_case, self).unlink( ids)
Пример #12
0
class Product(DeactivableMixin, ModelSQL, ModelView, CompanyMultiValueMixin):
    "Product Variant"
    __name__ = "product.product"
    _order_name = 'rec_name'
    template = fields.Many2One('product.template',
                               'Product Template',
                               required=True,
                               ondelete='CASCADE',
                               select=True,
                               states=STATES,
                               depends=DEPENDS)
    code = fields.Char("Code",
                       size=None,
                       select=True,
                       states=STATES,
                       depends=DEPENDS)
    cost_price = fields.MultiValue(
        fields.Numeric("Cost Price",
                       required=True,
                       digits=price_digits,
                       states=STATES,
                       depends=DEPENDS))
    cost_prices = fields.One2Many('product.cost_price', 'product',
                                  "Cost Prices")
    description = fields.Text("Description",
                              translate=True,
                              states=STATES,
                              depends=DEPENDS)
    list_price_uom = fields.Function(
        fields.Numeric('List Price', digits=price_digits), 'get_price_uom')
    cost_price_uom = fields.Function(
        fields.Numeric('Cost Price', digits=price_digits), 'get_price_uom')

    @classmethod
    def __setup__(cls):
        pool = Pool()
        Template = pool.get('product.template')

        if not hasattr(cls, '_no_template_field'):
            cls._no_template_field = set()
        cls._no_template_field.update(['products'])

        super(Product, cls).__setup__()

        for attr in dir(Template):
            tfield = getattr(Template, attr)
            if not isinstance(tfield, fields.Field):
                continue
            if attr in cls._no_template_field:
                continue
            field = getattr(cls, attr, None)
            if not field or isinstance(field, TemplateFunction):
                setattr(cls, attr, TemplateFunction(copy.deepcopy(tfield)))
                order_method = getattr(cls, 'order_%s' % attr, None)
                if (not order_method and not isinstance(
                        tfield,
                    (fields.Function, fields.One2Many, fields.Many2Many))):
                    order_method = TemplateFunction.order(attr)
                    setattr(cls, 'order_%s' % attr, order_method)
                if isinstance(tfield, fields.One2Many):
                    getattr(cls, attr).setter = '_set_template_function'

    @classmethod
    def _set_template_function(cls, products, name, value):
        # Prevent NotImplementedError for One2Many
        pass

    @fields.depends('template')
    def on_change_template(self):
        for name, field in self._fields.items():
            if isinstance(field, TemplateFunction):
                if self.template:
                    value = getattr(self.template, name, None)
                else:
                    value = None
                setattr(self, name, value)

    def get_template(self, name):
        value = getattr(self.template, name)
        if isinstance(value, Model):
            return value.id
        elif (isinstance(value, (list, tuple)) and value
              and isinstance(value[0], Model)):
            return [r.id for r in value]
        else:
            return value

    @classmethod
    def multivalue_model(cls, field):
        pool = Pool()
        if field == 'cost_price':
            return pool.get('product.cost_price')
        return super(Product, cls).multivalue_model(field)

    @classmethod
    def default_cost_price(cls, **pattern):
        return Decimal(0)

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

    @classmethod
    def order_rec_name(cls, tables):
        pool = Pool()
        Template = pool.get('product.template')
        product, _ = tables[None]
        if 'template' not in tables:
            template = Template.__table__()
            tables['template'] = {
                None: (template, product.template == template.id),
            }
        else:
            template = tables['template']
        return [product.code] + Template.name.convert_order(
            'name', tables['template'], Template)

    def get_rec_name(self, name):
        if self.code:
            return '[' + self.code + '] ' + self.name
        else:
            return self.name

    @classmethod
    def search_rec_name(cls, name, clause):
        if clause[1].startswith('!') or clause[1].startswith('not '):
            bool_op = 'AND'
        else:
            bool_op = 'OR'
        code_value = clause[2]
        if clause[1].endswith('like'):
            code_value = lstrip_wildcard(clause[2])
        return [
            bool_op,
            ('code', clause[1], code_value) + tuple(clause[3:]),
            ('template.name', ) + tuple(clause[1:]),
        ]

    @staticmethod
    def get_price_uom(products, name):
        Uom = Pool().get('product.uom')
        res = {}
        field = name[:-4]
        if Transaction().context.get('uom'):
            to_uom = Uom(Transaction().context['uom'])
        else:
            to_uom = None
        for product in products:
            price = getattr(product, field)
            if to_uom and product.default_uom.category == to_uom.category:
                res[product.id] = Uom.compute_price(product.default_uom, price,
                                                    to_uom)
            else:
                res[product.id] = price
        return res

    @classmethod
    def search_global(cls, text):
        for id_, rec_name, icon in super(Product, cls).search_global(text):
            icon = icon or 'tryton-product'
            yield id_, rec_name, icon
Пример #13
0
class ImportCSVColumn(ModelSQL, ModelView):
    'Import CSV Column'
    __name__ = 'import.csv.column'
    profile_csv = fields.Many2One('import.csv',
                                  'Import CSV',
                                  required=True,
                                  ondelete='CASCADE')
    column = fields.Char(
        'Columns',
        required=False,
        states={'invisible': Bool(Eval('constant'))},
        help=('The position of the CSV columns separated by commas '
              'to get the content of this field. First one is 0.'))
    constant = fields.Char(
        'Constant',
        states={'invisible': Bool(Eval('column'))},
        help='A constant value to set in this field.',
    )
    field = fields.Many2One('ir.model.field',
                            'Field',
                            domain=[('model', '=',
                                     Eval('_parent_profile_csv',
                                          {}).get('model'))],
                            select=True,
                            required=True)
    field_type = fields.Function(fields.Char('Field Type'),
                                 'on_change_with_field_type')
    submodel = fields.Function(fields.Many2One('ir.model', 'Submodel'),
                               'on_change_with_submodel')
    subfield = fields.Many2One(
        'ir.model.field',
        'Subfield',
        domain=[('model', '=', Eval('submodel'))],
        states={
            'invisible': ~Eval('field_type').in_(['one2many', 'many2many']),
            'required': Eval('field_type').in_(['one2many', 'many2many']),
        },
        depends=['field_type', 'submodel'],
        select=True)
    ttype = fields.Function(fields.Char('Field Type'), 'on_change_with_ttype')
    date_format = fields.Char(
        'Date Format',
        states={
            'invisible':
            Not(
                In(Eval('ttype'), [
                    'datetime', 'date', 'timestamp', 'time', 'many2one',
                    'one2many', 'many2many'
                ])),
            'required':
            In(Eval('ttype'), ['datetime', 'date', 'timestamp', 'time']),
        },
        help=(
            'Set the CSV format of the DateTime, Date or Timestamp data.\n\n'
            '%d: Day.\t\t\t\t%H: Hours.\n'
            '%m: Month.\t\t\t%M: Minutes.\n'
            '%Y: Year.\t\t\t\t%S: Seconds.\n\n'
            'Use commas to separate more than one field.\n\n'
            'Eg:\n\n%d/%m/%Y,%H:%M:%S\n\n'
            'Will match date and time from two fields like \'13/01/2015\' and '
            '\'17:01:56\'\n\n'
            'To see more information visit: '
            'https://docs.python.org/2/library/datetime.html'
            '?highlight=datetime#strftime-and-strptime-behavior'))
    add_to_domain = fields.Boolean(
        'Add to Domain',
        help='If checked, adds this field to domain for searching records in '
        'order to avoid duplicates.')
    selection = fields.Text(
        'Selection',
        states={
            'invisible': Eval('ttype') != 'selection',
        },
        depends=['ttype'],
        help='A couple of key and value separated by ":" per line')

    @classmethod
    def __setup__(cls):
        super(ImportCSVColumn, cls).__setup__()
        cls._order = [
            ('column', 'ASC'),
            ('id', 'DESC'),
        ]
        cls._error_messages.update({
            'columns_must_be_integers':
            ('Columns on field \'%s\' must be integers separated by '
             'commas.'),
            'numeric_format_error':
            ('Error importing numeric.\n'
             'Possible causes:\n\n'
             '\t- The format of the number is wrong.\n'
             '\t- The csv file has a header and you does not checked '
             'the box on the wizard.\n\n'
             'Field: \'%s\'\n'
             'Value: \'%s\'\n'),
            'datetime_format_error':
            ('Error importing DateTime, Date or '
             'Time.\n'
             'Possible causes:\n\n'
             '\t- The format of the date is wrong.\n'
             '\t- The csv file has a header and you does not checked '
             'the box on the wizard.\n\n'
             'Field: \'%s\'\n'
             'Value: \'%s\'\n'
             'Format: \'%s\''),
            'char_encoding_error':
            ('Error importing Char.\n'
             'Possible causes:\n\n'
             '\t- The character encoding of the file is wrong.\n'
             'Field: \'%s\'\n'),
            'integer_too_big_error':
            ('Error importing integer.\n'
             'Field \'%s\' has a very big number:\n'
             'Value: \'%s\'\n'
             'Value must be between -2147483648 and 2147483647'),
            'integer_format_error':
            ('Error importing integer.\n'
             'Possible causes:\n\n'
             '\t- The format of the number is wrong.\n'
             '\t- The csv file has a header and you does not checked '
             'the box on the wizard.\n\n'
             'Field: \'%s\'\n'
             'Value: \'%s\'\n'),
            'boolean_format_error':
            ('Error importing boolean.\n'
             'Possible causes:\n\n'
             '\t- The format of the boolean is wrong.\n'
             '\t- The csv file has a header and you does not checked '
             'the box on the wizard.\n\n'
             'Field: \'%s\'\n'
             'Value: \'%s\'\n'),
            'column_and_constant_null_error':
            ('The "Columns" and '
             '"Constant" fields of line %s can not be empty at the '
             'ame time. Please fill at least one of them.'),
        })

    @fields.depends('field')
    def on_change_with_field_type(self, name=None):
        if self.field:
            return self.field.ttype
        return ''

    @fields.depends('field', '_parent_profile_csv.model')
    def on_change_with_submodel(self, name=None):
        Model = Pool().get('ir.model')

        if getattr(self, 'profile_csv'):
            profile_model = self.profile_csv.model
        elif 'model' in Transaction().context:
            profile_model = Model(Transaction().context.get('model'))
        else:
            return None

        ProfileModel = Pool().get(profile_model.model)

        if (self.field
                and self.field.ttype in ['many2one', 'one2many', 'many2many']):
            field = ProfileModel._fields[self.field.name]
            relation = field.get_target().__name__
            models = Model.search([('model', '=', relation)])
            return models[0].id if models else None
        return None

    @classmethod
    def validate(cls, records):
        super(ImportCSVColumn, cls).validate(records)
        cls.check_sources(records)
        cls.check_columns(records)

    @classmethod
    def check_sources(cls, columns):
        for column in columns:
            if not column.column and not column.constant:
                cls.raise_user_error('column_and_constant_null_error',
                                     error_args=(column.field.name, ))

    @classmethod
    def check_columns(cls, columns):
        for column in columns:
            cells = column.column
            if not cells:
                continue
            cells = cells.split(',')
            for cell in cells:
                try:
                    int(cell)
                except ValueError:
                    cls.raise_user_error('columns_must_be_integers',
                                         error_args=(column.field.name, ))

    def field_required(self):
        field = Pool().get(self.field.model.model)
        return (field._fields[self.field.name].required
                or field._fields[self.field.name].states.get(
                    'required', False))

    @fields.depends('field')
    def on_change_with_ttype(self, name=None):
        if self.field:
            return self.field.ttype

    @property
    def digits(self):
        digits = 4
        if self.field.ttype in ('float', 'numeric'):
            Model = Pool().get(self.field.model.model)
            digits = Model._fields.get(self.field.name).digits[1]
            if isinstance(digits, PYSON):
                digits = PYSONDecoder().decode(PYSONEncoder().encode(digits))
        return digits

    def get_numeric(self, values):
        for value in values:
            quantize = Decimal(10)**-Decimal(self.digits)
            thousands_separator = self.profile_csv.thousands_separator
            decimal_separator = self.profile_csv.decimal_separator
            if thousands_separator != 'none':
                value = value.replace(thousands_separator, '')
            if decimal_separator == ',':
                value = value.replace(decimal_separator, '.')
            try:
                value = Decimal(value).quantize(quantize)
            except:
                self.raise_user_error('numeric_format_error',
                                      error_args=(self.field.name, value))
            return value

    def get_char(self, values):
        result = ''
        for value in values:
            character_encoding = self.profile_csv.character_encoding
            # Python3 strings can not be decoded
            if hasattr(value, 'decode'):
                try:
                    value = value.decode(character_encoding)
                except:
                    self.raise_user_error('char_encoding_error',
                                          error_args=(self.field.name))
            if result:
                result += ', ' + value
            else:
                result = value
        return result

    def get_text(self, values):
        return self.get_char(values)

    def get_integer(self, values):
        for value in values:
            try:
                value = int(value)
            except:
                self.raise_user_error('integer_format_error',
                                      error_args=(self.field.name, value))
            if value < -2147483648 or value > 2147483647:
                self.raise_user_error('integer_too_big_error',
                                      error_args=(self.field.name, value))
            return value

    def get_datetime(self, values):
        for value in values:
            date_format = self.date_format
            try:
                value = datetime.strptime(value, date_format)
            except ValueError:
                self.raise_user_error('datetime_format_error',
                                      error_args=(self.field.name, value,
                                                  date_format))
            return value

    def get_date(self, values):
        value = self.get_datetime(values)
        return date(value.year, value.month, value.day)

    def get_time(self, values):
        for value in values:
            date_format = self.date_format
            try:
                value = time.strptime(value, date_format)
            except ValueError:
                self.raise_user_error('datetime_format_error',
                                      error_args=(self.field.name, value,
                                                  date_format))
            return value

    def get_timestamp(self, values):
        return self.get_datetime(values)

    def get_boolean(self, values):
        for value in values:
            try:
                value = bool(value)
            except:
                self.raise_user_error('boolean_format_error',
                                      error_args=(self.field.name, value))
            return value

    def get_selection(self, values):
        value = self.get_char([values[0]])
        map_values = self.selection or u''
        if map_values:
            for pair in map_values.splitlines():
                if pair:
                    key, map_value = pair.split(':')
                    if key == value:
                        value = map_value.strip()
                        break
        return value

    def get_many2one(self, values):
        Model = Pool().get(self.field.relation)
        records = Model.search([
            ('name', '=', values[0]),
        ])
        if records:
            return records[0]
        else:
            return

    def get_one2many(self, values):
        return values[0]

    def get_many2many(self, values):
        # TODO
        pass

    def get_value(self, values):
        if values and values[0]:
            return getattr(self, 'get_%s' % self.ttype)(values)
        elif self.constant:
            return getattr(self, 'get_%s' % self.ttype)([self.constant])
Пример #14
0
class DocumentType(ModelSQL, ModelView):
    """
    Elastic Search Document Type Definition

    This will in future be used for the mapping too.
    """
    __name__ = "elasticsearch.document.type"

    name = fields.Char('Name', required=True)
    model = fields.Many2One('ir.model', 'Model', required=True, select=True)
    trigger = fields.Many2One('ir.trigger',
                              'Trigger',
                              required=False,
                              ondelete='RESTRICT')
    mapping = fields.Text('Mapping', required=True)

    @staticmethod
    def default_mapping():
        return '{}'

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

        # TODO: add a unique constraint on model
        cls._buttons.update({
            'update_mapping': {},
            'reindex_all_records': {},
            'get_default_mapping': {},
        })
        cls._error_messages.update({
            'wrong_mapping':
            'Mapping does not seem to be valid JSON',
        })

    @classmethod
    def create(cls, document_types):
        "Create records and make appropriate triggers"
        # So that we don't modify the original data passed
        document_types = [dt.copy() for dt in document_types]
        for document_type in document_types:
            document_type['trigger'] = cls._trigger_create(
                document_type['name'], document_type['model']).id
        return super(DocumentType, cls).create(document_types)

    @classmethod
    def write(cls, document_types, values):
        "Update records and add/remove triggers appropriately"
        Trigger = Pool().get('ir.trigger')

        if 'trigger' in values:
            raise UserError("Updating Trigger manually is not allowed!")

        triggers_to_delete = []
        for document_type in document_types:
            triggers_to_delete.append(document_type.trigger)

            values_new = values.copy()
            # so that we don't change the original values passed to us
            trigger = cls._trigger_create(
                values_new.get('name', document_type.name),
                values_new.get('model', document_type.model.id))
            values_new['trigger'] = trigger.id
            super(DocumentType, cls).write([document_type], values_new)

        Trigger.delete(triggers_to_delete)

    @classmethod
    def delete(cls, document_types):
        "Delete records and remove associated triggers"
        Trigger = Pool().get('ir.trigger')

        triggers_to_delete = [dt.trigger for dt in document_types]
        super(DocumentType, cls).delete(document_types)
        Trigger.delete(triggers_to_delete)

    @classmethod
    def _trigger_create(cls, name, model):
        """Create trigger for model

        :param name: Name of the DocumentType used as Trigger name
        :param model: Model id
        """
        Trigger = Pool().get('ir.trigger')
        Model = Pool().get('ir.model')

        index_model = Model(model)
        action_model, = Model.search([
            ('model', '=', cls.__name__),
        ])

        return Trigger.create([{
            'name': "elasticsearch_%s" % name,
            'model': index_model.id,
            'on_create': True,
            'on_write': True,
            'on_delete': True,
            'action_model': action_model.id,
            'condition': 'True',
            'action_function': '_trigger_handler',
        }])[0]

    @classmethod
    def _trigger_handler(cls, records, trigger):
        "Handler called by trigger"
        return IndexBacklog.create_from_records(records)

    @classmethod
    def validate(cls, document_types):
        "Validate the records"
        super(DocumentType, cls).validate(document_types)
        for document_type in document_types:
            document_type.check_mapping()

    def check_mapping(self):
        """
        Check if it is possible to at least load the JSON
        as a check for its validity
        """
        try:
            json.loads(self.mapping)
        except:
            self.raise_user_error('wrong_mapping')

    @classmethod
    @ModelView.button
    def reindex_all_records(cls, document_types):
        """
        Reindex all of the records in this model

        :param document_types: Document Types
        """
        IndexBacklog = Pool().get('elasticsearch.index_backlog')

        for document_type in document_types:
            Model = Pool().get(document_type.model.model)
            records = Model.search([])

            # Performance speedups
            index_backlog_create = IndexBacklog.create
            model_name = Model.__name__

            vlist = []
            for record in records:
                vlist.append({
                    'record_model': model_name,
                    'record_id': record.id,
                })
            index_backlog_create(vlist)

    @classmethod
    @ModelView.button
    def get_default_mapping(cls, document_types):
        """
        Tries to get the default mapping from the model object
        """
        for document_type in document_types:
            Model = Pool().get(document_type.model.model)
            if hasattr(Model, 'es_mapping'):
                cls.write(
                    [document_type],
                    {'mapping': json.dumps(Model.es_mapping(), indent=4)})
            else:
                cls.raise_user_error("Model %s has no mapping specified" %
                                     Model.__name__)

    @classmethod
    @ModelView.button
    def update_mapping(cls, document_types):
        """
        Update the mapping on the server side
        """
        config = Pool().get('elasticsearch.configuration')(1)

        conn = config.get_es_connection()

        for document_type in document_types:
            conn.indices.put_mapping(
                config.make_type_name(document_type.model.model),  # Type
                json.loads(document_type.mapping),  # Mapping
                [config.index_name],  # Index
            )
Пример #15
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'})
Пример #16
0
class OpenStatementDone(ModelView):
    'Open Statement'
    __name__ = 'open.statement.done'
    result = fields.Text('Result', readonly=True)
Пример #17
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)
Пример #18
0
class CloseStatementDone(ModelView):
    'Close Statement'
    __name__ = 'close.statement.done'
    result = fields.Text('Result', readonly=True)
Пример #19
0
class ContactMechanism(DeactivableMixin, sequence_ordered(), ModelSQL,
                       ModelView):
    "Contact Mechanism"
    __name__ = 'party.contact_mechanism'
    _rec_name = 'value'

    type = fields.Selection(_TYPES,
                            'Type',
                            required=True,
                            states=STATES,
                            sort=False,
                            depends=DEPENDS)
    value = fields.Char(
        'Value',
        select=True,
        states=STATES,
        depends=DEPENDS
        # Add all function fields to ensure to always fill them via on_change
        + ['email', 'website', 'skype', 'sip', 'other_value', 'value_compact'])
    value_compact = fields.Char('Value Compact', readonly=True)
    name = fields.Char("Name", states=STATES, depends=DEPENDS)
    comment = fields.Text('Comment', states=STATES, depends=DEPENDS)
    party = fields.Many2One('party.party',
                            'Party',
                            required=True,
                            ondelete='CASCADE',
                            states=STATES,
                            select=True,
                            depends=DEPENDS)
    email = fields.Function(fields.Char('E-Mail',
                                        states={
                                            'invisible':
                                            Eval('type') != 'email',
                                            'required':
                                            Eval('type') == 'email',
                                            'readonly': ~Eval('active', True),
                                        },
                                        depends=['value', 'type', 'active']),
                            'get_value',
                            setter='set_value')
    website = fields.Function(fields.Char('Website',
                                          states={
                                              'invisible':
                                              Eval('type') != 'website',
                                              'required':
                                              Eval('type') == 'website',
                                              'readonly':
                                              ~Eval('active', True),
                                          },
                                          depends=['value', 'type', 'active']),
                              'get_value',
                              setter='set_value')
    skype = fields.Function(fields.Char('Skype',
                                        states={
                                            'invisible':
                                            Eval('type') != 'skype',
                                            'required':
                                            Eval('type') == 'skype',
                                            'readonly': ~Eval('active', True),
                                        },
                                        depends=['value', 'type', 'active']),
                            'get_value',
                            setter='set_value')
    sip = fields.Function(fields.Char('SIP',
                                      states={
                                          'invisible': Eval('type') != 'sip',
                                          'required': Eval('type') == 'sip',
                                          'readonly': ~Eval('active', True),
                                      },
                                      depends=['value', 'type', 'active']),
                          'get_value',
                          setter='set_value')
    other_value = fields.Function(
        fields.Char('Value',
                    states={
                        'invisible':
                        Eval('type').in_(['email', 'website', 'skype', 'sip']),
                        'required':
                        ~Eval('type').in_(['email', 'website']),
                        'readonly':
                        ~Eval('active', True),
                    },
                    depends=['value', 'type', 'active']),
        'get_value',
        setter='set_value')
    url = fields.Function(
        fields.Char('URL', states={
            'invisible': ~Eval('url'),
        }), 'on_change_with_url')

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

    @staticmethod
    def default_type():
        return 'phone'

    @classmethod
    def get_value(cls, mechanisms, names):
        return dict((name, dict((m.id, m.value) for m in mechanisms))
                    for name in names)

    @fields.depends('type', 'value')
    def on_change_with_url(self, name=None, value=None):
        if value is None:
            value = self.value
        if self.type == 'email':
            return 'mailto:%s' % value
        elif self.type == 'website':
            return value
        elif self.type == 'skype':
            return 'callto:%s' % value
        elif self.type == 'sip':
            return 'sip:%s' % value
        elif self.type == 'phone':
            return 'tel:%s' % value
        elif self.type == 'fax':
            return 'fax:%s' % value
        return None

    @fields.depends('party', '_parent_party.addreses')
    def _phone_country_codes(self):
        if self.party:
            for address in self.party.addresses:
                if address.country:
                    yield address.country.code

    @fields.depends(methods=['_phone_country_codes'])
    def _parse_phonenumber(self, value):
        for country_code in chain(self._phone_country_codes(), [None]):
            try:
                # Country code is ignored if value has an international prefix
                return phonenumbers.parse(value, country_code)
            except NumberParseException:
                pass
        return None

    @fields.depends(methods=['_parse_phonenumber'])
    def format_value(self, value=None, type_=None):
        if phonenumbers and type_ in _PHONE_TYPES:
            phonenumber = self._parse_phonenumber(value)
            if phonenumber:
                value = phonenumbers.format_number(
                    phonenumber, PhoneNumberFormat.INTERNATIONAL)
        return value

    @fields.depends(methods=['_parse_phonenumber'])
    def format_value_compact(self, value=None, type_=None):
        if phonenumbers and type_ in _PHONE_TYPES:
            phonenumber = self._parse_phonenumber(value)
            if phonenumber:
                value = phonenumbers.format_number(phonenumber,
                                                   PhoneNumberFormat.E164)
        return value

    @classmethod
    def set_value(cls, mechanisms, name, value):
        #  Setting value is done by on_changes
        pass

    @fields.depends(
        methods=['on_change_with_url', 'format_value', 'format_value_compact'])
    def _change_value(self, value, type_):
        self.value = self.format_value(value=value, type_=type_)
        self.value_compact = self.format_value_compact(value=value,
                                                       type_=type_)
        self.website = value
        self.email = value
        self.skype = value
        self.sip = value
        self.other_value = value
        self.url = self.on_change_with_url(value=value)

    @fields.depends('value', 'type', methods=['_change_value'])
    def on_change_value(self):
        return self._change_value(self.value, self.type)

    @fields.depends('website', 'type', methods=['_change_value'])
    def on_change_website(self):
        return self._change_value(self.website, self.type)

    @fields.depends('email', 'type', methods=['_change_value'])
    def on_change_email(self):
        return self._change_value(self.email, self.type)

    @fields.depends('skype', 'type', methods=['_change_value'])
    def on_change_skype(self):
        return self._change_value(self.skype, self.type)

    @fields.depends('sip', 'type', methods=['_change_value'])
    def on_change_sip(self):
        return self._change_value(self.sip, self.type)

    @fields.depends('other_value', 'type', methods=['_change_value'])
    def on_change_other_value(self):
        return self._change_value(self.other_value, self.type)

    @classmethod
    def search_rec_name(cls, name, clause):
        return [
            'OR',
            ('value', ) + tuple(clause[1:]),
            ('value_compact', ) + tuple(clause[1:]),
        ]

    @classmethod
    def _format_values(cls, mechanisms):
        for mechanism in mechanisms:
            value = mechanism.format_value(value=mechanism.value,
                                           type_=mechanism.type)
            if value != mechanism.value:
                mechanism.value = value
            value_compact = mechanism.format_value_compact(
                value=mechanism.value, type_=mechanism.type)
            if value_compact != mechanism.value_compact:
                mechanism.value_compact = value_compact
        cls.save(mechanisms)

    @classmethod
    def create(cls, vlist):
        mechanisms = super(ContactMechanism, cls).create(vlist)
        cls._format_values(mechanisms)
        return mechanisms

    @classmethod
    def write(cls, *args):
        actions = iter(args)
        all_mechanisms = []
        for mechanisms, values in zip(actions, actions):
            all_mechanisms.extend(mechanisms)
            if 'party' in values:
                for mechanism in mechanisms:
                    if mechanism.party.id != values['party']:
                        raise AccessError(
                            gettext('party'
                                    '.msg_contact_mechanism_change_party') % {
                                        'contact': mechanism.rec_name,
                                    })
        super(ContactMechanism, cls).write(*args)
        cls._format_values(all_mechanisms)

    @classmethod
    def validate(cls, mechanisms):
        super(ContactMechanism, cls).validate(mechanisms)
        for mechanism in mechanisms:
            mechanism.check_valid_phonenumber()

    def check_valid_phonenumber(self):
        if not phonenumbers or self.type not in _PHONE_TYPES:
            return
        phonenumber = self._parse_phonenumber(self.value)
        if not (phonenumber and phonenumbers.is_valid_number(phonenumber)):
            raise InvalidPhoneNumber(
                gettext('party.msg_invalid_phone_number',
                        phone=self.value,
                        party=self.party.rec_name))

    @classmethod
    def usages(cls, _fields=None):
        "Returns the selection list of usage"
        usages = [(None, "")]
        if _fields:
            for name, desc in cls.fields_get(_fields).items():
                usages.append((name, desc['string']))
        return usages
Пример #20
0
class View(ModelSQL, ModelView):
    "View"
    __name__ = 'ir.ui.view'
    _rec_name = 'model'
    model = fields.Char('Model', select=True, states={
            'required': Eval('type').in_([None, 'tree', 'form', 'graph']),
            })
    priority = fields.Integer('Priority', required=True, select=True)
    type = fields.Selection([
            (None, ''),
            ('tree', 'Tree'),
            ('form', 'Form'),
            ('graph', 'Graph'),
            ('calendar', 'Calendar'),
            ('board', 'Board'),
            ], 'View Type', select=True,
        domain=[
            If(Bool(Eval('inherit')),
                ('type', '=', None),
                ('type', '!=', None)),
            ],
        depends=['inherit'])
    data = fields.Text('Data')
    name = fields.Char('Name', states={
            'invisible': ~(Eval('module') & Eval('name')),
            }, depends=['module'], readonly=True)
    arch = fields.Function(fields.Text('View Architecture', states={
                'readonly': Bool(Eval('name')),
                }, depends=['name']), 'get_arch', setter='set_arch')
    inherit = fields.Many2One('ir.ui.view', 'Inherited View', select=True,
            ondelete='CASCADE')
    field_childs = fields.Char('Children Field', states={
            'invisible': Eval('type') != 'tree',
            }, depends=['type'])
    module = fields.Char('Module', states={
            'invisible': ~Eval('module'),
            }, readonly=True)
    domain = fields.Char('Domain', states={
            'invisible': ~Eval('inherit'),
            }, depends=['inherit'])
    _get_rng_cache = Cache('ir_ui_view.get_rng')

    @classmethod
    def __setup__(cls):
        super(View, cls).__setup__()
        cls._error_messages.update({
                'invalid_xml': 'Invalid XML for view "%s".',
                })
        cls._order.insert(0, ('priority', 'ASC'))
        cls._buttons.update({
                'show': {
                    'readonly': Eval('type') != 'form',
                    'depends': ['type'],
                    },
                })

    @staticmethod
    def default_priority():
        return 16

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

    @classmethod
    @ModelView.button_action('ir.act_view_show')
    def show(cls, views):
        pass

    @classmethod
    def get_rng(cls, type_):
        key = (cls.__name__, type_)
        rng = cls._get_rng_cache.get(key)
        if rng is None:
            rng_name = os.path.join(os.path.dirname(__file__), type_ + '.rng')
            with open(rng_name, 'rb') as fp:
                rng = etree.fromstring(fp.read())
            cls._get_rng_cache.set(key, rng)
        return rng

    @property
    def rng_type(self):
        if self.inherit:
            return self.inherit.rng_type
        return self.type

    @classmethod
    def validate(cls, views):
        super(View, cls).validate(views)
        cls.check_xml(views)

    @classmethod
    def check_xml(cls, views):
        "Check XML"
        for view in views:
            if not view.arch:
                continue
            xml = view.arch.strip()
            if not xml:
                continue
            tree = etree.fromstring(xml)

            if hasattr(etree, 'RelaxNG'):
                validator = etree.RelaxNG(etree=cls.get_rng(view.rng_type))
                if not validator.validate(tree):
                    error_log = '\n'.join(map(str,
                            validator.error_log.filter_from_errors()))
                    logger.error('Invalid XML view %s:\n%s\n%s',
                        view.rec_name, error_log, xml)
                    cls.raise_user_error(
                        'invalid_xml', (view.rec_name,), error_log)
            root_element = tree.getroottree().getroot()

            # validate pyson attributes
            validates = {
                'states': fields.states_validate,
            }

            def encode(element):
                for attr in ('states', 'domain', 'spell'):
                    if not element.get(attr):
                        continue
                    try:
                        value = PYSONDecoder().decode(element.get(attr))
                        validates.get(attr, lambda a: True)(value)
                    except Exception as e:
                        error_log = '%s: <%s %s="%s"/>' % (
                            e, element.get('id') or element.get('name'), attr,
                            element.get(attr))
                        logger.error(
                            'Invalid XML view %s:\n%s\n%s',
                            view.rec_name, error_log, xml)
                        cls.raise_user_error(
                            'invalid_xml', (view.rec_name,), error_log)
                for child in element:
                    encode(child)
            encode(root_element)

    def get_arch(self, name):
        value = None
        if self.name and self.module:
            path = os.path.join(self.module, 'view', self.name + '.xml')
            try:
                with file_open(path,
                        subdir='modules', mode='r', encoding='utf-8') as fp:
                    value = fp.read()
            except IOError:
                pass
        if not value:
            value = self.data
        return value

    @classmethod
    def set_arch(cls, views, name, value):
        cls.write(views, {'data': value})

    @classmethod
    def delete(cls, views):
        super(View, cls).delete(views)
        # Restart the cache
        ModelView._fields_view_get_cache.clear()

    @classmethod
    def create(cls, vlist):
        views = super(View, cls).create(vlist)
        # Restart the cache
        ModelView._fields_view_get_cache.clear()
        return views

    @classmethod
    def write(cls, views, values, *args):
        super(View, cls).write(views, values, *args)
        # Restart the cache
        ModelView._fields_view_get_cache.clear()
Пример #21
0
class PediatricSymptomsChecklist(ModelSQL, ModelView):
    'Pediatric Symptoms Checklist'
    __name__ = 'gnuhealth.patient.psc'

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

    evaluation_date = fields.Many2One(
        'gnuhealth.appointment',
        'Appointment',
        help="Enter or select the date / ID of the appointment related to "
        "this evaluation")

    evaluation_start = fields.DateTime('Date', required=True)

    user_id = fields.Many2One('res.user', 'Healh Professional', readonly=True)

    notes = fields.Text('Notes')

    psc_aches_pains = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                       'Complains of aches and pains',
                                       sort=False)

    psc_spend_time_alone = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                            'Spends more time alone',
                                            sort=False)

    psc_tires_easily = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                        'Tires easily, has little energy',
                                        sort=False)

    psc_fidgety = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                   'Fidgety, unable to sit still',
                                   sort=False)

    psc_trouble_with_teacher = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                                'Has trouble with teacher',
                                                sort=False)

    psc_less_interest_in_school = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                                   'Less interested in school',
                                                   sort=False)

    psc_acts_as_driven_by_motor = fields.Selection(
        [
            (None, ''),
            ('0', 'Never'),
            ('1', 'Sometimes'),
            ('2', 'Often'),
        ],
        'Acts as if driven by a motor',
        sort=False)

    psc_daydreams_too_much = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                              'Daydreams too much',
                                              sort=False)

    psc_distracted_easily = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                             'Distracted easily',
                                             sort=False)

    psc_afraid_of_new_situations = fields.Selection(
        [
            (None, ''),
            ('0', 'Never'),
            ('1', 'Sometimes'),
            ('2', 'Often'),
        ],
        'Is afraid of new situations',
        sort=False)

    psc_sad_unhappy = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                       'Feels sad, unhappy',
                                       sort=False)

    psc_irritable_angry = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                           'Is irritable, angry',
                                           sort=False)

    psc_feels_hopeless = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                          'Feels hopeless',
                                          sort=False)

    psc_trouble_concentrating = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                                 'Has trouble concentrating',
                                                 sort=False)

    psc_less_interested_in_friends = fields.Selection(
        [
            (None, ''),
            ('0', 'Never'),
            ('1', 'Sometimes'),
            ('2', 'Often'),
        ],
        'Less interested in friends',
        sort=False)

    psc_fights_with_others = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                              'Fights with other children',
                                              sort=False)

    psc_absent_from_school = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                              'Absent from school',
                                              sort=False)

    psc_school_grades_dropping = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                                  'School grades dropping',
                                                  sort=False)

    psc_down_on_self = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                        'Is down on him or herself',
                                        sort=False)

    psc_visit_doctor_finds_ok = fields.Selection(
        [
            (None, ''),
            ('0', 'Never'),
            ('1', 'Sometimes'),
            ('2', 'Often'),
        ],
        'Visits the doctor with doctor finding nothing wrong',
        sort=False)

    psc_trouble_sleeping = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                            'Has trouble sleeping',
                                            sort=False)

    psc_worries_a_lot = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                         'Worries a lot',
                                         sort=False)

    psc_wants_to_be_with_parents = fields.Selection(
        [
            (None, ''),
            ('0', 'Never'),
            ('1', 'Sometimes'),
            ('2', 'Often'),
        ],
        'Wants to be with you more than before',
        sort=False)

    psc_feels_is_bad_child = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                              'Feels he or she is bad',
                                              sort=False)

    psc_takes_unnecesary_risks = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                                  'Takes unnecessary risks',
                                                  sort=False)

    psc_gets_hurt_often = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                           'Gets hurt frequently',
                                           sort=False)

    psc_having_less_fun = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                           'Seems to be having less fun',
                                           sort=False)

    psc_act_as_younger = fields.Selection(
        [
            (None, ''),
            ('0', 'Never'),
            ('1', 'Sometimes'),
            ('2', 'Often'),
        ],
        'Acts younger than children his or her age',
        sort=False)

    psc_does_not_listen_to_rules = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                                    'Does not listen to rules',
                                                    sort=False)

    psc_does_not_show_feelings = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                                  'Does not show feelings',
                                                  sort=False)

    psc_does_not_get_people_feelings = fields.Selection(
        [
            (None, ''),
            ('0', 'Never'),
            ('1', 'Sometimes'),
            ('2', 'Often'),
        ],
        'Does not get people feelings',
        sort=False)

    psc_teases_others = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                         'Teases others',
                                         sort=False)

    psc_blames_others = fields.Selection(
        [
            (None, ''),
            ('0', 'Never'),
            ('1', 'Sometimes'),
            ('2', 'Often'),
        ],
        'Blames others for his or her troubles',
        sort=False)

    psc_takes_things_from_others = fields.Selection(
        [
            (None, ''),
            ('0', 'Never'),
            ('1', 'Sometimes'),
            ('2', 'Often'),
        ],
        'Takes things that do not belong to him or her',
        sort=False)

    psc_refuses_to_share = fields.Selection([
        (None, ''),
        ('0', 'Never'),
        ('1', 'Sometimes'),
        ('2', 'Often'),
    ],
                                            'Refuses to share',
                                            sort=False)

    psc_total = fields.Integer(
        'PSC Total',
        on_change_with=[
            'psc_aches_pains', 'psc_spend_time_alone', 'psc_tires_easily',
            'psc_fidgety', 'psc_trouble_with_teacher',
            'psc_less_interest_in_school', 'psc_acts_as_driven_by_motor',
            'psc_daydreams_too_much', 'psc_distracted_easily',
            'psc_afraid_of_new_situations', 'psc_sad_unhappy',
            'psc_irritable_angry', 'psc_feels_hopeless',
            'psc_trouble_concentrating', 'psc_less_interested_in_friends',
            'psc_fights_with_others', 'psc_absent_from_school',
            'psc_school_grades_dropping', 'psc_down_on_self',
            'psc_visit_doctor_finds_ok', 'psc_trouble_sleeping',
            'psc_worries_a_lot', 'psc_wants_to_be_with_parents',
            'psc_feels_is_bad_child', 'psc_takes_unnecesary_risks',
            'psc_gets_hurt_often', 'psc_having_less_fun', 'psc_act_as_younger',
            'psc_does_not_listen_to_rules', 'psc_does_not_show_feelings',
            'psc_does_not_get_people_feelings', 'psc_teases_others',
            'psc_takes_things_from_others', 'psc_refuses_to_share'
        ])

    @staticmethod
    def default_user_id():
        User = Pool().get('res.user')
        user = User(Transaction().user)
        return int(user.id)

    @staticmethod
    def default_psc_total():
        return 0

    def on_change_with_psc_total(self):

        psc_aches_pains = self.psc_aches_pains or '0'
        psc_spend_time_alone = self.psc_spend_time_alone or '0'
        psc_tires_easily = self.psc_tires_easily or '0'
        psc_fidgety = self.psc_fidgety or '0'
        psc_trouble_with_teacher = self.psc_trouble_with_teacher or '0'
        psc_less_interest_in_school = self.psc_less_interest_in_school or '0'
        psc_acts_as_driven_by_motor = self.psc_acts_as_driven_by_motor or '0'
        psc_daydreams_too_much = self.psc_daydreams_too_much or '0'
        psc_distracted_easily = self.psc_distracted_easily or '0'
        psc_afraid_of_new_situations = self.psc_afraid_of_new_situations or '0'
        psc_sad_unhappy = self.psc_sad_unhappy or '0'
        psc_irritable_angry = self.psc_irritable_angry or '0'
        psc_feels_hopeless = self.psc_feels_hopeless or '0'
        psc_trouble_concentrating = self.psc_trouble_concentrating or '0'
        psc_less_interested_in_friends = \
                self.psc_less_interested_in_friends or '0'
        psc_fights_with_others = self.psc_fights_with_others or '0'
        psc_absent_from_school = self.psc_absent_from_school or '0'
        psc_school_grades_dropping = self.psc_school_grades_dropping or '0'
        psc_down_on_self = self.psc_down_on_self or '0'
        psc_visit_doctor_finds_ok = self.psc_visit_doctor_finds_ok or '0'
        psc_trouble_sleeping = self.psc_trouble_sleeping or '0'
        psc_worries_a_lot = self.psc_worries_a_lot or '0'
        psc_wants_to_be_with_parents = self.psc_wants_to_be_with_parents or '0'
        psc_feels_is_bad_child = self.psc_feels_is_bad_child or '0'
        psc_takes_unnecesary_risks = self.psc_takes_unnecesary_risks or '0'
        psc_gets_hurt_often = self.psc_gets_hurt_often or '0'
        psc_having_less_fun = self.psc_having_less_fun or '0'
        psc_act_as_younger = self.psc_act_as_younger or '0'
        psc_does_not_listen_to_rules = self.psc_does_not_listen_to_rules or '0'
        psc_does_not_show_feelings = self.psc_does_not_show_feelings or '0'
        psc_does_not_get_people_feelings = \
                self.psc_does_not_get_people_feelings or '0'
        psc_teases_others = self.psc_teases_others or '0'
        psc_takes_things_from_others = self.psc_takes_things_from_others or '0'
        psc_refuses_to_share = self.psc_refuses_to_share or '0'

        psc_total = int(psc_aches_pains) + int(psc_spend_time_alone) + \
            int(psc_tires_easily) + int(psc_fidgety) + \
            int(psc_trouble_with_teacher) + \
            int(psc_less_interest_in_school) + \
            int(psc_acts_as_driven_by_motor) + \
            int(psc_daydreams_too_much) + int(psc_distracted_easily) + \
            int(psc_afraid_of_new_situations) + int(psc_sad_unhappy) + \
            int(psc_irritable_angry) + int(psc_feels_hopeless) + \
            int(psc_trouble_concentrating) + \
            int(psc_less_interested_in_friends) + \
            int(psc_fights_with_others) + int(psc_absent_from_school) + \
            int(psc_school_grades_dropping) + int(psc_down_on_self) + \
            int(psc_visit_doctor_finds_ok) + int(psc_trouble_sleeping) + \
            int(psc_worries_a_lot) + int(psc_wants_to_be_with_parents) + \
            int(psc_feels_is_bad_child) + int(psc_takes_unnecesary_risks) + \
            int(psc_gets_hurt_often) + int(psc_having_less_fun) + \
            int(psc_act_as_younger) + int(psc_does_not_listen_to_rules) + \
            int(psc_does_not_show_feelings) + \
            int(psc_does_not_get_people_feelings) + \
            int(psc_teases_others) + \
            int(psc_takes_things_from_others) + \
            int(psc_refuses_to_share)

        return psc_total
Пример #22
0
class ViewTreeState(ModelSQL, ModelView):
    'View Tree State'
    __name__ = 'ir.ui.view_tree_state'
    _rec_name = 'model'
    model = fields.Char('Model', required=True)
    domain = fields.Char('Domain', required=True)
    user = fields.Many2One('res.user', 'User', required=True,
            ondelete='CASCADE')
    child_name = fields.Char('Child Name')
    nodes = fields.Text('Expanded Nodes')
    selected_nodes = fields.Text('Selected Nodes')

    @classmethod
    def __setup__(cls):
        super(ViewTreeState, cls).__setup__()
        cls.__rpc__.update({
                'set': RPC(readonly=False, check_access=False),
                'get': RPC(check_access=False),
                })

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

        table = cls.__table_handler__(module_name)
        table.index_action(['model', 'domain', 'user', 'child_name'], 'add')

    @staticmethod
    def default_nodes():
        return '[]'

    @staticmethod
    def default_selected_nodes():
        return '[]'

    @classmethod
    def set(cls, model, domain, child_name, nodes, selected_nodes):
        # Normalize the json domain
        domain = json.dumps(json.loads(domain), separators=(',', ':'))
        current_user = Transaction().user
        records = cls.search([
                ('user', '=', current_user),
                ('model', '=', model),
                ('domain', '=', domain),
                ('child_name', '=', child_name),
                ])
        cls.delete(records)
        cls.create([{
                    'user': current_user,
                    'model': model,
                    'domain': domain,
                    'child_name': child_name,
                    'nodes': nodes,
                    'selected_nodes': selected_nodes,
                    }])

    @classmethod
    def get(cls, model, domain, child_name):
        # Normalize the json domain
        domain = json.dumps(json.loads(domain), separators=(',', ':'))
        current_user = Transaction().user
        try:
            expanded_info, = cls.search([
                    ('user', '=', current_user),
                    ('model', '=', model),
                    ('domain', '=', domain),
                    ('child_name', '=', child_name),
                    ],
                limit=1)
        except ValueError:
            return (cls.default_nodes(), cls.default_selected_nodes())
        state = cls(expanded_info)
        return (state.nodes or cls.default_nodes(),
            state.selected_nodes or cls.default_selected_nodes())
Пример #23
0
class Payment:
    __metaclass__ = PoolMeta
    __name__ = 'account.payment'

    sepa_mandate = fields.Many2One('account.payment.sepa.mandate', 'Mandate',
        ondelete='RESTRICT',
        domain=[
            ('party', '=', Eval('party', -1)),
            ('company', '=', Eval('company', -1)),
            ],
        depends=['party', 'company'])
    sepa_mandate_sequence_type = fields.Char('Mandate Sequence Type',
        readonly=True)
    sepa_return_reason_code = fields.Char('Return Reason Code', readonly=True,
        states={
            'invisible': (~Eval('sepa_return_reason_code')
                & (Eval('state') != 'failed')),
            },
        depends=['state'])
    sepa_return_reason_information = fields.Text('Return Reason Information',
        readonly=True,
        states={
            'invisible': (~Eval('sepa_return_reason_information')
                & (Eval('state') != 'failed')),
            },
        depends=['state'])
    sepa_end_to_end_id = fields.Function(fields.Char('SEPA End To End ID'),
        'get_sepa_end_to_end_id', searcher='search_end_to_end_id')
    sepa_instruction_id = fields.Function(fields.Char('SEPA Instruction ID'),
        'get_sepa_instruction_id', searcher='search_sepa_instruction_id')

    @classmethod
    def copy(cls, payments, default=None):
        if default is None:
            default = {}
        default.setdefault('sepa_mandate_sequence_type', None)
        return super(Payment, cls).copy(payments, default=default)

    @classmethod
    def get_sepa_mandates(cls, payments):
        mandates = []
        for payment in payments:
            if payment.sepa_mandate:
                if payment.sepa_mandate.is_valid:
                    mandate = payment.sepa_mandate
                else:
                    mandate = None
            else:
                for mandate in payment.party.sepa_mandates:
                    if mandate.is_valid:
                        break
                else:
                    mandate = None
            mandates.append(mandate)
        return mandates

    def get_sepa_end_to_end_id(self, name):
        return str(self.id)

    @classmethod
    def search_end_to_end_id(cls, name, domain):
        table = cls.__table__()
        _, operator, value = domain
        cast = cls.sepa_end_to_end_id._field.sql_type().base
        Operator = fields.SQL_OPERATORS[operator]
        query = table.select(table.id,
            where=Operator(table.id.cast(cast), value))
        return [('id', 'in', query)]

    get_sepa_instruction_id = get_sepa_end_to_end_id
    search_sepa_instruction_id = search_end_to_end_id

    @property
    def sepa_remittance_information(self):
        if self.description:
            return self.description
        elif self.line and self.line.origin:
            return self.line.origin.rec_name

    @property
    def sepa_bank_account_number(self):
        if self.kind == 'receivable':
            if self.sepa_mandate:
                return self.sepa_mandate.account_number
        else:
            for account in self.party.bank_accounts:
                for number in account.numbers:
                    if number.type == 'iban':
                        return number

    @property
    def rejected(self):
        return (self.state == 'failed'
            and self.sepa_return_reason_code
            and self.sepa_return_reason_information == '/RTYP/RJCT')

    def create_clearing_move(self, date=None):
        if not date:
            date = Transaction().context.get('date_value')
        return super(Payment, self).create_clearing_move(date=date)
Пример #24
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
Пример #25
0
class ContactMechanism(sequence_ordered(), ModelSQL, ModelView):
    "Contact Mechanism"
    __name__ = 'party.contact_mechanism'
    _rec_name = 'value'

    type = fields.Selection(_TYPES,
                            'Type',
                            required=True,
                            states=STATES,
                            sort=False,
                            depends=DEPENDS)
    value = fields.Char(
        'Value',
        select=True,
        states=STATES,
        depends=DEPENDS
        # Add all function fields to ensure to always fill them via on_change
        + ['email', 'website', 'skype', 'sip', 'other_value', 'value_compact'])
    value_compact = fields.Char('Value Compact', readonly=True)
    comment = fields.Text('Comment', states=STATES, depends=DEPENDS)
    party = fields.Many2One('party.party',
                            'Party',
                            required=True,
                            ondelete='CASCADE',
                            states=STATES,
                            select=True,
                            depends=DEPENDS)
    active = fields.Boolean(
        'Active',
        select=True,
        help="Uncheck to exclude the contact mechanism from future use.")
    email = fields.Function(fields.Char('E-Mail',
                                        states={
                                            'invisible':
                                            Eval('type') != 'email',
                                            'required':
                                            Eval('type') == 'email',
                                            'readonly': ~Eval('active', True),
                                        },
                                        depends=['value', 'type', 'active']),
                            'get_value',
                            setter='set_value')
    website = fields.Function(fields.Char('Website',
                                          states={
                                              'invisible':
                                              Eval('type') != 'website',
                                              'required':
                                              Eval('type') == 'website',
                                              'readonly':
                                              ~Eval('active', True),
                                          },
                                          depends=['value', 'type', 'active']),
                              'get_value',
                              setter='set_value')
    skype = fields.Function(fields.Char('Skype',
                                        states={
                                            'invisible':
                                            Eval('type') != 'skype',
                                            'required':
                                            Eval('type') == 'skype',
                                            'readonly': ~Eval('active', True),
                                        },
                                        depends=['value', 'type', 'active']),
                            'get_value',
                            setter='set_value')
    sip = fields.Function(fields.Char('SIP',
                                      states={
                                          'invisible': Eval('type') != 'sip',
                                          'required': Eval('type') == 'sip',
                                          'readonly': ~Eval('active', True),
                                      },
                                      depends=['value', 'type', 'active']),
                          'get_value',
                          setter='set_value')
    other_value = fields.Function(
        fields.Char('Value',
                    states={
                        'invisible':
                        Eval('type').in_(['email', 'website', 'skype', 'sip']),
                        'required':
                        ~Eval('type').in_(['email', 'website']),
                        'readonly':
                        ~Eval('active', True),
                    },
                    depends=['value', 'type', 'active']),
        'get_value',
        setter='set_value')
    url = fields.Function(
        fields.Char(
            'URL',
            states={
                'invisible': (~Eval('type').in_(
                    ['email', 'website', 'skype', 'sip', 'fax', 'phone'])
                              | ~Eval('url')),
            },
            depends=['type']), 'get_url')

    @classmethod
    def __setup__(cls):
        super(ContactMechanism, cls).__setup__()
        cls._order.insert(0, ('party', 'ASC'))
        cls._error_messages.update({
            'write_party': ('You can not modify the party of contact '
                            'mechanism "%s".'),
            'invalid_phonenumber': ('The phone number "%(phone)s" of '
                                    'party "%(party)s" is not valid .'),
        })

    @classmethod
    def __register__(cls, module_name):
        TableHandler = backend.get('TableHandler')
        table = TableHandler(cls, module_name)

        super(ContactMechanism, cls).__register__(module_name)

        # Migration from 2.4: drop required on sequence
        table.not_null_action('sequence', action='remove')

    @staticmethod
    def default_type():
        return 'phone'

    @staticmethod
    def default_active():
        return True

    @classmethod
    def get_value(cls, mechanisms, names):
        return dict((name, dict((m.id, m.value) for m in mechanisms))
                    for name in names)

    def get_url(self, name=None, value=None):
        if value is None:
            value = self.value
        if self.type == 'email':
            return 'mailto:%s' % value
        elif self.type == 'website':
            return value
        elif self.type == 'skype':
            return 'callto:%s' % value
        elif self.type == 'sip':
            return 'sip:%s' % value
        elif self.type == 'phone':
            return 'tel:%s' % value
        elif self.type == 'fax':
            return 'fax:%s' % value
        return None

    @classmethod
    def format_value(cls, value=None, type_=None):
        if phonenumbers and type_ in _PHONE_TYPES:
            try:
                phonenumber = phonenumbers.parse(value)
            except NumberParseException:
                pass
            else:
                value = phonenumbers.format_number(
                    phonenumber, PhoneNumberFormat.INTERNATIONAL)
        return value

    @classmethod
    def format_value_compact(cls, value=None, type_=None):
        if phonenumbers and type_ in _PHONE_TYPES:
            try:
                phonenumber = phonenumbers.parse(value)
            except NumberParseException:
                pass
            else:
                value = phonenumbers.format_number(phonenumber,
                                                   PhoneNumberFormat.E164)
        return value

    @classmethod
    def set_value(cls, mechanisms, name, value):
        #  Setting value is done by on_changes
        pass

    def _change_value(self, value, type_):
        self.value = self.format_value(value=value, type_=type_)
        self.value_compact = self.format_value_compact(value=value,
                                                       type_=type_)
        self.website = value
        self.email = value
        self.skype = value
        self.sip = value
        self.other_value = value
        self.url = self.get_url(value=value)

    @fields.depends('value', 'type')
    def on_change_type(self):
        self.url = self.get_url(value=self.value)

    @fields.depends('value', 'type')
    def on_change_value(self):
        return self._change_value(self.value, self.type)

    @fields.depends('website', 'type')
    def on_change_website(self):
        return self._change_value(self.website, self.type)

    @fields.depends('email', 'type')
    def on_change_email(self):
        return self._change_value(self.email, self.type)

    @fields.depends('skype', 'type')
    def on_change_skype(self):
        return self._change_value(self.skype, self.type)

    @fields.depends('sip', 'type')
    def on_change_sip(self):
        return self._change_value(self.sip, self.type)

    @fields.depends('other_value', 'type')
    def on_change_other_value(self):
        return self._change_value(self.other_value, self.type)

    @classmethod
    def search_rec_name(cls, name, clause):
        return [
            'OR',
            ('value', ) + tuple(clause[1:]),
            ('value_compact', ) + tuple(clause[1:]),
        ]

    @classmethod
    def _format_values(cls, mechanisms):
        for mechanism in mechanisms:
            value = mechanism.format_value(value=mechanism.value,
                                           type_=mechanism.type)
            if value != mechanism.value:
                mechanism.value = value
            value_compact = mechanism.format_value_compact(
                value=mechanism.value, type_=mechanism.type)
            if value_compact != mechanism.value_compact:
                mechanism.value_compact = value_compact
        cls.save(mechanisms)

    @classmethod
    def create(cls, vlist):
        mechanisms = super(ContactMechanism, cls).create(vlist)
        cls._format_values(mechanisms)
        return mechanisms

    @classmethod
    def write(cls, *args):
        actions = iter(args)
        all_mechanisms = []
        for mechanisms, values in zip(actions, actions):
            all_mechanisms.extend(mechanisms)
            if 'party' in values:
                for mechanism in mechanisms:
                    if mechanism.party.id != values['party']:
                        cls.raise_user_error('write_party',
                                             (mechanism.rec_name, ))
        super(ContactMechanism, cls).write(*args)
        cls._format_values(all_mechanisms)

    @classmethod
    def validate(cls, mechanisms):
        super(ContactMechanism, cls).validate(mechanisms)
        for mechanism in mechanisms:
            mechanism.check_valid_phonenumber()

    def check_valid_phonenumber(self):
        if not phonenumbers or self.type not in _PHONE_TYPES:
            return
        try:
            phonenumber = phonenumbers.parse(self.value)
        except NumberParseException:
            phonenumber = None
        if not (phonenumber and phonenumbers.is_valid_number(phonenumber)):
            self.raise_user_error('invalid_phonenumber', {
                'phone': self.value,
                'party': self.party.rec_name
            })
Пример #26
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
Пример #27
0
class Asset(ModelSQL, ModelView):
    """
    Fleet Management Asset
    """
    _name = "fleet.asset"
    _rec_name = 'code'
    _description = "Fleet Management Asset"

    code = fields.Char('Code', required=True, select=1)
    meter_unit = fields.Many2One("product.uom",
                                 "Meter Unit",
                                 required=True,
                                 domain=[('category.name', '=', 'Length')])
    status = fields.Selection([
        ('Active', 'Active'),
        ('Out of Service', 'Out of Service'),
    ],
                              "Status",
                              readonly=True,
                              select=1)
    average_fuel_efficiency = fields.Function(
        fields.Numeric("Average Fuel Efficiency", loading="lazy"),
        'get_avg_efficiency')

    # Specifications
    year = fields.Integer("Year")
    make = fields.Char("Make")
    model = fields.Char("Model", select=1)
    serial_number = fields.Char("Serial Number")
    license_plate = fields.Char("Plate Number", select=1)

    # Purchase
    vendor = fields.Many2One("party.party", "Vendor")
    purchase_date = fields.Date("Purchase Date")
    purchase_meter = fields.BigInteger("Purchase Meter")
    warranty_expiration_date = fields.Date("Warranty Expiration Date")
    warranty_expiration_meter = fields.BigInteger("Warranty Expiration Meter")

    # Status
    in_service_date = fields.Date("In Service Date")
    out_of_service_date = fields.Date("Out of Service Date")

    # Comments
    comment = fields.Text('Comment')

    def default_year(self):
        """Get the current year
        """
        date_obj = Pool().get('ir.date')
        return date_obj.today().year

    def get_avg_efficiency(self, ids, name):
        """
        Get average efficiency of the fuel
        """
        purchase_line_obj = Pool().get('purchase.line')
        res = {}
        for asset in self.browse(ids):
            sum_quantity = 0
            purchase_line_ids = purchase_line_obj.search(
                [('asset', '=', asset.id)], order=[('id', 'DESC')], limit=100)
            for purchase_line in purchase_line_obj.browse(purchase_line_ids):
                sum_quantity += Decimal(str(purchase_line.quantity))

            if purchase_line_ids:
                # get the last purchase line for particular asset.
                last_line = purchase_line_obj.browse(purchase_line_ids[-1])
                # get the first purchase line from last 100 records
                # for particular asset.
                first_line = purchase_line_obj.browse(purchase_line_ids[0])
                if len(purchase_line_ids) == 1:
                    avg_efficiency = (first_line.meter_reading - \
                        0)/Decimal(str(purchase_line.quantity))
                else:
                    avg_efficiency = (first_line.meter_reading - \
                        last_line.meter_reading) / (sum_quantity)
            else:
                avg_efficiency = 0
            res[asset.id] = avg_efficiency
        return res
Пример #28
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)
Пример #29
0
class AddressFormat(DeactivableMixin, MatchMixin, ModelSQL, ModelView):
    "Address Format"
    __name__ = 'party.address.format'
    country_code = fields.Char("Country Code", size=2)
    language_code = fields.Char("Language Code", size=2)
    format_ = fields.Text("Format",
                          required=True,
                          help="Available variables (also in upper case):\n"
                          "- ${party_name}\n"
                          "- ${name}\n"
                          "- ${attn}\n"
                          "- ${street}\n"
                          "- ${postal_code}\n"
                          "- ${city}\n"
                          "- ${subdivision}\n"
                          "- ${subdivision_code}\n"
                          "- ${country}\n"
                          "- ${country_code}")

    _get_format_cache = Cache('party.address.format.get_format')

    @classmethod
    def __setup__(cls):
        super(AddressFormat, cls).__setup__()
        cls._order.insert(0, ('country_code', 'ASC NULLS LAST'))
        cls._order.insert(1, ('language_code', 'ASC NULLS LAST'))

    @classmethod
    def __register__(cls, module_name):
        pool = Pool()
        Country = pool.get('country.country')
        Language = pool.get('ir.lang')
        country = Country.__table__()
        language = Language.__table__()
        table = cls.__table__()
        cursor = Transaction().connection.cursor()

        super().__register__(module_name)

        table_h = cls.__table_handler__()

        # Migration from 5.2: replace country by country_code
        if table_h.column_exist('country'):
            query = table.update([table.country_code],
                                 country.select(
                                     country.code,
                                     where=country.id == table.country))
            cursor.execute(*query)
            table_h.drop_column('country')

        # Migration from 5.2: replace language by language_code
        if table_h.column_exist('language'):
            query = table.update([table.language_code],
                                 language.select(
                                     Substring(language.code, 0, 2),
                                     where=language.id == table.language))
            cursor.execute(*query)
            table_h.drop_column('language')

    @classmethod
    def default_format_(cls):
        return """${party_name}
${name}
${street}
${postal_code} ${city}
${subdivision}
${COUNTRY}"""

    @classmethod
    def create(cls, *args, **kwargs):
        records = super(AddressFormat, cls).create(*args, **kwargs)
        cls._get_format_cache.clear()
        return records

    @classmethod
    def write(cls, *args, **kwargs):
        super(AddressFormat, cls).write(*args, **kwargs)
        cls._get_format_cache.clear()

    @classmethod
    def delete(cls, *args, **kwargs):
        super(AddressFormat, cls).delete(*args, **kwargs)
        cls._get_format_cache.clear()

    @classmethod
    def validate(cls, formats):
        super(AddressFormat, cls).validate(formats)
        for format_ in formats:
            format_.check_format()

    def check_format(self):
        pool = Pool()
        Address = pool.get('party.address')
        address = Address()
        try:
            Template(self.format_).substitute(
                **address._get_address_substitutions())
        except Exception as exception:
            raise InvalidFormat(
                gettext('party.invalid_format',
                        format=self.format_,
                        exception=exception)) from exception

    @classmethod
    def get_format(cls, address, pattern=None):
        if pattern is None:
            pattern = {}
        else:
            pattern = pattern.copy()
        pattern.setdefault('country_code',
                           address.country.code if address.country else None)
        pattern.setdefault('language_code', Transaction().language[:2])

        key = tuple(sorted(pattern.items()))
        format_ = cls._get_format_cache.get(key)
        if format_ is not None:
            return format_

        for record in cls.search([]):
            if record.match(pattern):
                format_ = record.format_
                break
        else:
            format_ = cls.default_format_()

        cls._get_format_cache.set(key, format_)
        return format_
Пример #30
0
class ResultsReportVersionDetail(metaclass=PoolMeta):
    __name__ = 'lims.results_report.version.detail'

    template = fields.Many2One('lims.report.template',
                               'Report Template',
                               domain=[
                                   ('report_name', '=', 'lims.result_report'),
                                   ('type', 'in', [None, 'base']),
                               ],
                               states={'readonly': Eval('state') != 'draft'},
                               depends=['state'])
    template_type = fields.Function(
        fields.Selection([
            (None, ''),
            ('base', 'HTML'),
            ('header', 'HTML - Header'),
            ('footer', 'HTML - Footer'),
        ], 'Report Template Type'), 'get_template_type')
    sections = fields.One2Many('lims.results_report.version.detail.section',
                               'version_detail', 'Sections')
    previous_sections = fields.Function(fields.One2Many(
        'lims.results_report.version.detail.section',
        'version_detail',
        'Previous Sections',
        domain=[('position', '=', 'previous')]),
                                        'get_previous_sections',
                                        setter='set_previous_sections')
    following_sections = fields.Function(fields.One2Many(
        'lims.results_report.version.detail.section',
        'version_detail',
        'Following Sections',
        domain=[('position', '=', 'following')]),
                                         'get_following_sections',
                                         setter='set_following_sections')
    trend_charts = fields.One2Many(
        'lims.results_report.version.detail.trend.chart', 'version_detail',
        'Trend Charts')
    charts_x_row = fields.Selection([
        ('1', '1'),
        ('2', '2'),
    ], 'Charts per Row')
    comments_plain = fields.Function(fields.Text('Comments', translate=True),
                                     'get_comments_plain',
                                     setter='set_comments_plain')

    @classmethod
    def __setup__(cls):
        super().__setup__()
        if 'invisible' in cls.resultrange_origin.states:
            del cls.resultrange_origin.states['invisible']
        if 'required' in cls.resultrange_origin.states:
            del cls.resultrange_origin.states['required']

    @classmethod
    def view_attributes(cls):
        return super().view_attributes() + [
            ('//page[@id="comments"]', 'states', {
                'invisible': Not(Bool(Eval('template_type'))),
            }),
            ('//page[@id="comments_plain"]', 'states', {
                'invisible': Eval('template_type') == 'base',
            }),
        ]

    @staticmethod
    def default_charts_x_row():
        return '1'

    def get_template_type(self, name):
        return self.template and self.template.type or None

    @fields.depends('template', '_parent_template.trend_charts',
                    '_parent_template.sections', 'sections',
                    'resultrange_origin')
    def on_change_template(self):
        if (self.template and self.template.resultrange_origin
                and not self.resultrange_origin):
            self.resultrange_origin = self.template.resultrange_origin.id
        if self.template and self.template.trend_charts:
            self.trend_charts = [{
                'chart': c.chart.id,
                'order': c.order,
            } for c in self.template.trend_charts]
            self.charts_x_row = self.template.charts_x_row
        if self.template and self.template.sections:
            sections = {}
            for s in self.sections + self.template.sections:
                sections[s.name] = {
                    'name': s.name,
                    'data': s.data,
                    'data_id': s.data_id,
                    'position': s.position,
                    'order': s.order,
                }
            self.sections = sections.values()

    def get_previous_sections(self, name):
        return [s.id for s in self.sections if s.position == 'previous']

    @classmethod
    def set_previous_sections(cls, sections, name, value):
        if not value:
            return
        cls.write(sections, {'sections': value})

    def get_following_sections(self, name):
        return [s.id for s in self.sections if s.position == 'following']

    @classmethod
    def set_following_sections(cls, sections, name, value):
        if not value:
            return
        cls.write(sections, {'sections': value})

    @classmethod
    def _get_fields_from_samples(cls, samples, generate_report_form=None):
        pool = Pool()
        Notebook = pool.get('lims.notebook')

        detail_default = super()._get_fields_from_samples(
            samples, generate_report_form)

        result_template = None
        if generate_report_form and generate_report_form.template:
            result_template = generate_report_form.template
        resultrange_origin = None

        for sample in samples:
            nb = Notebook(sample['notebook'])
            if not result_template:
                result_template = cls._get_result_template_from_sample(nb)
            if not resultrange_origin:
                resultrange_origin = cls._get_resultrange_from_sample(nb)

        if result_template:
            detail_default['template'] = result_template.id
            if not resultrange_origin:
                resultrange_origin = result_template.resultrange_origin
            if result_template.trend_charts:
                detail_default['trend_charts'] = [('create', [{
                    'chart':
                    c.chart.id,
                    'order':
                    c.order,
                } for c in result_template.trend_charts])]
                detail_default['charts_x_row'] = (result_template.charts_x_row)
            if result_template.sections:
                detail_default['sections'] = [('create', [{
                    'name': s.name,
                    'data': s.data,
                    'data_id': s.data_id,
                    'position': s.position,
                    'order': s.order,
                } for s in result_template.sections])]

        if resultrange_origin:
            detail_default['resultrange_origin'] = resultrange_origin.id

        return detail_default

    @classmethod
    def _get_result_template_from_sample(cls, notebook):
        pool = Pool()
        Service = pool.get('lims.service')
        Laboratory = pool.get('lims.laboratory')
        Configuration = pool.get('lims.configuration')

        result_template = notebook.fraction.sample.result_template
        if not result_template:
            ok = True
            services = Service.search([
                ('fraction', '=', notebook.fraction),
                ('analysis.type', '=', 'group'),
                ('annulled', '=', False),
            ])
            for service in services:
                if service.analysis.result_template:
                    if not result_template:
                        result_template = service.analysis.result_template
                    elif result_template != service.analysis.result_template:
                        ok = False
                elif result_template:
                    ok = False
            if not ok:
                result_template = None

        if not result_template:
            laboratory_id = Transaction().context.get(
                'samples_pending_reporting_laboratory', None)
            if laboratory_id:
                laboratory = Laboratory(laboratory_id)
                result_template = laboratory.result_template

        if not result_template:
            config_ = Configuration(1)
            result_template = config_.result_template

        return result_template

    @classmethod
    def _get_resultrange_from_sample(cls, notebook):
        return notebook.fraction.sample.resultrange_origin

    @classmethod
    def _get_fields_not_overwrite(cls):
        fields = super()._get_fields_not_overwrite()
        fields.extend([
            'template', 'trend_charts', 'charts_x_row', 'sections',
            'resultrange_origin'
        ])
        return fields

    @classmethod
    def _get_fields_from_detail(cls, detail):
        detail_default = super()._get_fields_from_detail(detail)
        if detail.template:
            detail_default['template'] = detail.template.id
        if detail.trend_charts:
            detail_default['trend_charts'] = [('create', [{
                'chart': c.chart.id,
                'order': c.order,
            } for c in detail.trend_charts])]
            detail_default['charts_x_row'] = detail.charts_x_row
        if detail.sections:
            detail_default['sections'] = [('create', [{
                'name': s.name,
                'data': s.data,
                'data_id': s.data_id,
                'position': s.position,
                'order': s.order,
            } for s in detail.sections])]
        return detail_default

    def get_comments_plain(self, name):
        return self.comments

    @classmethod
    def set_comments_plain(cls, records, name, value):
        cls.write(records, {'comments': value})