Writing a statement to send sms once you create a user


I want a line of code to just send an sms once i create a person here is the code

class Party(ModelSQL, ModelView):
    __name__ = 'party.party'

    def person_age(self, name):
        return compute_age_from_dates(self.dob, self.deceased,
                              self.dod, self.gender, name, None)

    def get_du_address(self, name):
        if (self.du):
            return self.du.address_repr

    person_names = fields.One2Many('gnuhealth.person_name','party',
        'Person Names',
        states={'invisible': Not(Bool(Eval('is_person')))})

    name_representation = fields.Selection([
        (None, ''),
        ('pgfs', 'Prefix Given Family, Suffix'),
        ('gf', 'Given Family'),
        ('fg', 'Family, Given'),
        ], 'Name Representation',
        states={'invisible': Not(Bool(Eval('is_person')))})

    activation_date = fields.Date(
        'Activation date', help='Date of activation of the party')

    federation_account = fields.Char('Federation ID',
        help='Federation Account',
        states={'invisible': Not(Bool(Eval('is_person')))})

    ref = fields.Char(
        help='Person Unique Identifier',
        states={'invisible': Not(Bool(Eval('is_person')))})

    unidentified = fields.Boolean(
        help='Patient is currently unidentified',
        states={'invisible': Not(Bool(Eval('is_person')))})

    is_person = fields.Boolean(
        help='Check if the party is a person.')

    is_patient = fields.Boolean(
        states={'invisible': Not(Bool(Eval('is_person')))},
        help='Check if the party is a patient')

    is_healthprof = fields.Boolean(
        'Health Prof',
        states={'invisible': Not(Bool(Eval('is_person')))},
        help='Check if the party is a health professional')

    is_institution = fields.Boolean(
        'Institution', help='Check if the party is a Health Care Institution')
    is_insurance_company = fields.Boolean(
        'Insurance Company', help='Check if the party is an Insurance Company')
    is_pharmacy = fields.Boolean(
        'Pharmacy', help='Check if the party is a Pharmacy')
    from_ = fields.Char('PHONE NUMBER')
    lastname = fields.Char('Family names', help='Family or last names',
        states={'invisible': Not(Bool(Eval('is_person')))})
    dob = fields.Date('DoB', help='Date of Birth')

    age = fields.Function(fields.Char('Age'), 'person_age')

    gender = fields.Selection([
        (None, ''),
        ('m', 'Male'),
        ('f', 'Female'),
        ], 'Gender', states={'required': Bool(Eval('is_person'))})

    photo = fields.Binary('Picture')
    ethnic_group = fields.Many2One('gnuhealth.ethnicity', 'Ethnicity')

    marital_status = fields.Selection([
        (None, ''),
        ('s', 'Single'),
        ('m', 'Married'),
        ('c', 'Concubinage'),
        ('w', 'Widowed'),
        ('d', 'Divorced'),
        ('x', 'Separated'),
        ], 'Marital Status', sort=False)

    citizenship = fields.Many2One(
        'country.country', 'Citizenship', help='Country of Citizenship')
    residence = fields.Many2One(
        'country.country', 'Residence', help='Country of Residence')
    alternative_identification = fields.Boolean(
        'Alternative IDs', help='Other types of '
        'identification, not the official PUID . '
        'Examples : Passport, foreign ID,..')

    alternative_ids = fields.One2Many(
        'name', 'Alternative IDs',
        states={'invisible': Not(Bool(Eval('alternative_identification')))})

    insurance = fields.One2Many('gnuhealth.insurance', 'name', 'Insurances',
        help="Insurance Plans associated to this party")

    internal_user = fields.Many2One(
        'res.user', 'Internal User',
        help='In GNU Health is the user (person) '
        'that logins. When the'
        ' party is a person, it will be the user'
        ' that maps the party.',
            'invisible': Not(Bool(Eval('is_person'))),

    insurance_company_type = fields.Selection([
        (None, ''),
        ('state', 'State'),
        ('labour_union', 'Labour Union / Syndical'),
        ('private', 'Private'),
        ], 'Insurance Type', select=True)
    insurance_plan_ids = fields.One2Many(
        'gnuhealth.insurance.plan', 'company', 'Insurance Plans')

    du = fields.Many2One('gnuhealth.du', 'DU', help="Domiciliary Unit")

    du_address = fields.Function(
        fields.Text('Main address',
        help="Main Address, based on the associated DU"),'get_du_address')

    birth_certificate = fields.Many2One('gnuhealth.birth_certificate',
        'Birth Certificate', readonly=True)

    deceased = fields.Boolean('Deceased', readonly=True,
        help='The information is updated from the Death Certificate',
        states={'invisible': Not(Bool(Eval('deceased')))})

    dod = fields.Function(fields.DateTime(
        'Date of Death',
            'invisible': Not(Bool(Eval('deceased'))),

    death_certificate = fields.Many2One('gnuhealth.death_certificate',
        'Death Certificate', readonly=True)

    mother = fields.Function(
        help="Mother from the Birth Certificate"),'get_mother')

    father = fields.Function(
        help="Father from the Birth Certificate"),'get_father')

    fed_country = fields.Char('Prefix',
        help="3-letter Country code"
        "in ISO 3166-1 alpha-3 standard that will become the prefix"
        "of the federation account. The following user-assigned codes"
        "ranges can be also used"
        "AAA to AAZ, QMA to QZZ, XAA to XZZ, and ZZA to ZZZ."
        "For example XXX is unidentified nationality and XXB is a refugee."
        "By default, it will use the code of the emiting institution country"
        "Refer to the GNU Health manual for further information",
        states={'invisible': Not(Bool(Eval('is_person')))})

    def get_mother(self, name):
        if (self.birth_certificate and self.birth_certificate.mother):
            return self.birth_certificate.mother.id

    def get_father(self, name):
        if (self.birth_certificate and self.birth_certificate.father):
            return self.birth_certificate.father.id

    def get_dod(self, name):
        if (self.deceased and self.death_certificate):
            return self.death_certificate.dod

    def default_fed_country():
        Fedcountry = Pool().get('gnuhealth.federation.country.config')(1)
        if (Fedcountry and Fedcountry.country):
            return Fedcountry.code

    # Use the Federation country as default value for citizenship
    # and residence for newly created people
    def default_citizenship():
        Fedcountry = Pool().get('gnuhealth.federation.country.config')(1)
        if (Fedcountry and Fedcountry.country):
            return int(Fedcountry.country)

    def default_residence():
        Fedcountry = Pool().get('gnuhealth.federation.country.config')(1)
        if (Fedcountry and Fedcountry.country):
            return int(Fedcountry.country)

    def default_activation_date():
        return date.today()

    def generate_puid(cls):
        # Add a default random string in the ref field.
        # The STRSIZE constant provides the length of the PUID
        # The format of the PUID is XXXNNNXXX
        # By default, this field will be used only if nothing is entered

        STRSIZE = 9
        puid = ''
        for x in range(STRSIZE):
            if ( x < 3 or x > 5 ):
                puid = puid + random.choice(string.ascii_uppercase)
                puid = puid + random.choice(string.digits)
        return puid

    def convert_photo(cls, data):
        if data and Image:
            image = Image.open(BytesIO(data))
            image.thumbnail((200, 200), Image.ANTIALIAS)
            data = BytesIO()
            image.save(data, image.format)
            data = fields.Binary.cast(data.getvalue())
        return data

    def write(cls, *args):
        actions = iter(args)
        args = []
        for parties, vals in zip(actions, actions):
            vals = vals.copy()
            person_id = parties[0].id
            # We set the value to None to make the fields that have a
            # unique constraint get the NULL value at PostgreSQL level, and not
            # the value '' coming from the client
            if vals.get('ref') == '':
                vals['ref'] = None

            if vals.get('federation_account') == '':
                vals['federation_account'] = None

            if 'photo' in vals:
                vals['photo'] = cls.convert_photo(vals['photo'])

            if ('name' in vals) or ('lastname' in vals):
                if 'name' in vals:
                    given_name = vals['name']
                if 'lastname' in vals:

                if parties[0].is_person:


        return super(Party, cls).write(*args)

    def update_person_official_name(cls,person_id,given_name,family_name):
        # Create or update the official PersonName entry with the Given / Family
        # names from the main entry field.

        Pname = Pool().get('gnuhealth.person_name')
        officialnames = Pname.search(
            [("party", "=", person_id), ("use", "=", 'official')],)

        # If no official name found, create a new record
        if not (officialnames):
            values = {
                'party': person_id,
                'use': 'official',

            if given_name:
                values['given'] = given_name
            if family_name:
                values['family'] = family_name


        #Found a related official name record, then
        #update official Person Name(s) when modified in main form

            values = {'use': 'official'}

            if given_name:
                values['given'] = given_name
            if family_name:
                values['family'] = family_name

            Pname.write(official_rec, values)

    def create(cls, vlist):
        Configuration = Pool().get('party.configuration')

        vlist = [x.copy() for x in vlist]

        tmp_act = cls.generate_puid()

        for values in vlist:
            if not values.get('ref'):
                if values.get('federation_account'):
                        #Strip the country code from the fed account
                        #and pass it to the local PUID
                        values['ref'] = values.get('federation_account')[3:]
                    values['ref'] = tmp_act
                if 'unidentified' in values and values['unidentified']:
                    values['ref'] = 'NN-' + values.get('ref')
                if 'is_person' in values and not values['is_person']:
                    values['ref'] = 'NP-' + values['ref']

            # Generate the Federation account ID
            # with the ISO 3166-1 alpha-3 as prefix
            # using the same code as in the newly created PUID
            # If the person is NN or there is no country assigned
            # use the prefix XXX
            if not values.get('federation_account') and values.get('is_person'):
                    federation_account = tmp_act
                    values['federation_account'] = \
                        values['fed_country'] + federation_account

            # Set the value to None to make the fields that have a
            # unique constraint get the NULL value at PostgreSQL level, and not
            # the value '' coming from the client
            if values.get('federation_account') == '':
                values['federation_account'] = None

            #Generate internal code
            if not values.get('code'):
                config = Configuration(1)
                # Use the company name . Initially, use the name
                # since the company hasn't been created yet.
                suffix = Transaction().context.get('company.rec_name') \
                    or values['name']
                # Generate the party code in the form of
                # "UUID-" . Where company is the name of the Health
                # Institution.
                # The field "code" is the one that is used in distributed
                # environments, with multiple GNU Health instances across
                # a country / region
                values['code'] = '%s-%s' % (uuid4(), suffix)

            values.setdefault('addresses', None)

            if 'photo' in values:
                values['photo'] = cls.convert_photo(values['photo'])

            #If the party is a physical person,
            #add new PersonName record with the given and family name
            #as the official name

            if (values.get('is_person')):
                if ('name' in values) or ('lastname' in values):
                    official_name = []
                    given_name = family_name= ''

                    if 'name' in values:
                        given_name = values['name']
                    if 'lastname' in values:

                    official_name.append(('create', [{
                        'use': 'official',
                        'given': given_name,
                        'family': family_name,

                    values['person_names'] = official_name

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

    def __setup__(cls):
        super(Party, cls).__setup__()
        t = cls.__table__()
        cls._sql_constraints += [
            ('ref_uniq', Unique(t,t.ref), 'The PUID must be unique'),
            ('internal_user_uniq', Unique(t,t.internal_user),
                'This internal user is already assigned to a party'),
                'The Federation Account must be unique'),]

        cls._order.insert(0, ('lastname', 'ASC'))
        cls._order.insert(1, ('name', 'ASC'))
        #Sort to be used when called from other models.
        cls._order_name = 'lastname'

    def get_rec_name(self, name):
        #Display name on the following sequence
        # 1 - Oficial Name from PersonName with the name representation
        # If not offficial name :
        # 2 - Last name, First name

        if self.person_names:
            prefix = given = family = suffix = ''
            for pname in self.person_names:
                if pname.prefix:
                    prefix = pname.prefix + ' '
                if pname.suffix:
                    suffix = ', ' + pname.suffix

                given = pname.given or ''
                family = pname.family or ''

                if pname.use == 'official':
                    if self.name_representation == 'pgfs':
                        res = prefix + given + ' ' + family + suffix
                    if self.name_representation == 'gf':
                        if pname.family:
                            family = ' ' + pname.family
                        res = given + family
                    if self.name_representation == 'fg':
                        if pname.family:
                            family = pname.family + ', '
                        res = family + given

                    if not self.name_representation:
                        # Default value
                        if family:
                            return family + ', ' + given
                            return given
                return res

        if self.lastname:
            return self.lastname + ', ' + self.name
            return self.name

    def search_rec_name(cls, name, clause):
        """ Search for the name, lastname, PUID, any alternative IDs,
            and any family and / or given name from the person_names
        if clause[1].startswith('!') or clause[1].startswith('not '):
            bool_op = 'AND'
            bool_op = 'OR'
        return [bool_op,
            ('ref',) + tuple(clause[1:]),
            ('alternative_ids.code',) + tuple(clause[1:]),
            ('federation_account',) + tuple(clause[1:]),
            ('contact_mechanisms.value',) + tuple(clause[1:]),
            ('person_names.family',) + tuple(clause[1:]),
            ('person_names.given',) + tuple(clause[1:]),
            ('name',) + tuple(clause[1:]),
            ('lastname',) + tuple(clause[1:]),

    @fields.depends('is_person', 'is_patient', 'is_healthprof')
    def on_change_with_is_person(self):
        # Set is_person if the party is a health professional or a patient
        if (self.is_healthprof or self.is_patient or self.is_person):
            return True

    def on_change_with_du_address(self):
        if (self.du):
            return self.get_du_address(name=None)

    def validate(cls, parties):
        super(Party, cls).validate(parties)
        for party in parties:

    def validate_dob(self):
            Check that the date is sane
                * The person is alive
                * Non-negative years, months or days
                * < 200 (future generations :) )
        if (self.dob):
            years,months,days = \
                compute_age_from_dates(self.dob, self.deceased,
                              self.dod, self.gender, 'raw_age', None)

            if (not self.deceased):
                if (years < 0 or months < 0 or days < 0) or years > 200:
                        "Wrong date of birth for a living person")

    def check_person(self):
        # Verify that health professional and patient
        # are unchecked when is_person is False

        if not self.is_person and (self.is_patient or self.is_healthprof):
                "The Person field must be set if the party is a health"
                " professional or a patient")

    def validate_official_name(self):
        # Only allow one official name on the party name
        Pname = Pool().get('gnuhealth.person_name')
        officialnames = Pname.search_count(
            [("party", "=", self.id), ("use", "=", 'official')],)

        if (officialnames > 1):
                "The person can have only one official name")

    def view_attributes(cls):
        # Hide the group holding all the demographics when the party is not
        # a person
        return [('//group[@id="person_details"]', 'states', {
                'invisible': ~Eval('is_person'),


Note the from_ fileds is for the phone number input


Any body to help me out on this issues


If you could please tell me the statement that save the user i mean the button code

(David Harper) #5


I’m not totally clear on what you need to know, and I suspect others are in the same boat.

Sending a text message will require more than a single line of code.

There isn’t really any “button code” that directly saves a new record (user). The client handles any “button presses”, and will communicate with the server to perform the correct actions. On the server the def create(cls, vlist) function gets called to create one, or more, records (the documentation is here). In the code you posted the party.party model is being extended, and the create call in the return super(Party, cls).create(vlist) statement will ultimately create the record that represents the user - as long as the transaction it is running in ends up getting commited.


Ok thanks now i know i would just create a click space like active once clicked it would performe the task of getting the phone number fileds and send sms thanks or if you have any way or idea you can help out

(David Harper) #7

I’m sorry, but I have no idea what you mean by this.

You might want to consider using a trigger to call a method in a custom module that sends the sms message on creation of a new user.


Ok please how sorry if it may dusturb you am so confused, if you could just give me the code i would be happy and it would go a long way thanks

(David Harper) #9

What part are you finding confusing?

Do you already have some python code (that can be run outside of Tryton) that can send sms messages?


I have a python code to send sms from twilio what next is now creating the actual code that would be used to call the twillo sms code to send from input of phone number


So this is what i need now a code that would just performe the task of calling the comand sending sms once the user is create

(David Harper) #12

The actual code that you need will depend on which version of python and tryton you are running, and whether you are altering an existing module, or creating your own module to perform this action.

In both cases you will need to create a method in a class that inherits from trytond.model.model.Model (such as in the Party class in your code above), the method would be something like this:

def send_new_user_sms(cls, users, trigger):
    for user in users:
        name = user.name
        phone_number = user.from_
        YOUR_SEND_SMS_FUNCTION(phone_number, 'Welcome %s' % name)

You would then need to go into Tryton and open the Administration / Models / Triggers form and create a new record:

  • enter a name for the trigger (can be anything, so perhaps “send new user sms”)
  • check “On Create
  • enter the Model (this will be “Party”)
  • fill in the condition ("True")
  • the action model (this depends on the class you put the function in, but will probably be “Party” in your case)
  • and the action function ("send_new_user_sms").

The send_new_user_sms() function should then get called when new users are created, you can then turn this functionality off and on by de-activating and re-activating the trigger.


I so much love your effort am back on track with your help thanks