@webship.co/workspace-odoo 0.0.0-stage → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,129 @@
1
+ # The accounts of an Odoo site, and what keeps it local. Runs inside `odoo shell` in the Odoo
2
+ # container of the project (the shell provides `env` and `odoo`); the functions of the plugin
3
+ # (fun-odoo.sh) pipe it there and hand it what it needs in two variables:
4
+ #
5
+ # ODOO_ACCOUNTS_VERB one or more of local, owner, add, cancel, list, apps, with commas, run in
6
+ # that order
7
+ # ODOO_ACCOUNTS base64 of a JSON object:
8
+ # { owner: { name, email, password },
9
+ # accounts: [{ name, email, password, role }] }
10
+ #
11
+ # local The site stays local. The "partner_autocomplete" module, which Odoo installs on its
12
+ # own, sends what a user types in a company name to an outside service and mixes the
13
+ # answers into the proposals of the field. A local site must not depend on, or send
14
+ # data to, an outside service, so the module is uninstalled.
15
+ # owner The administrator Odoo created (admin / admin) becomes the workspace account.
16
+ # add The default accounts, each with the groups of its role. One that exists (the demo
17
+ # data has a portal user) gets its groups and its password again and keeps its name.
18
+ # cancel The default accounts are deleted; one that is part of the data of the site (the demo
19
+ # portal user), or that Odoo will not delete because records point at it, is archived.
20
+ # list Who is there. apps The applications that are installed.
21
+ #
22
+ # Every verb can run again. No password is ever printed.
23
+
24
+ import base64
25
+ import json
26
+ import os
27
+
28
+ from odoo import SUPERUSER_ID, api
29
+
30
+ GIVEN = json.loads(base64.b64decode(os.environ.get('ODOO_ACCOUNTS') or 'e30=').decode('utf-8'))
31
+ VERBS = [verb for verb in os.environ.get('ODOO_ACCOUNTS_VERB', '').split(',') if verb]
32
+
33
+ # The groups of each role, by external id. A group of an app that is not installed is left out.
34
+ ROLES = {
35
+ # Every app that is installed, and the settings.
36
+ 'administrator': ['base.group_user', 'base.group_system', 'base.group_partner_manager', 'sales_team.group_sale_manager',
37
+ 'account.group_account_manager', 'website.group_website_designer', 'event.group_event_manager',
38
+ 'hr_recruitment.group_hr_recruitment_manager'],
39
+ # Sales and CRM, own documents only; no Invoicing.
40
+ 'salesperson': ['base.group_user', 'sales_team.group_sale_salesman'],
41
+ # Invoicing; no Sales, no CRM.
42
+ 'accountant': ['base.group_user', 'account.group_account_invoice'],
43
+ # An internal user with no app-specific group.
44
+ 'employee': ['base.group_user'],
45
+ # A portal user: the website and /my, never the web client.
46
+ 'portal': ['base.group_portal'],
47
+ }
48
+
49
+ for verb in VERBS:
50
+ Users = env['res.users'].with_context(no_reset_password=True, active_test=False)
51
+ # The field that holds the groups of a user was renamed in a later release.
52
+ groups_field = 'groups_id' if 'groups_id' in Users._fields else 'group_ids'
53
+
54
+ if verb == 'local':
55
+ autocomplete = env['ir.module.module'].search([('name', '=', 'partner_autocomplete'), ('state', '=', 'installed')])
56
+ if autocomplete:
57
+ autocomplete.button_immediate_uninstall()
58
+ print(' partner_autocomplete is uninstalled: nothing a user types is sent to an outside service.')
59
+ # The uninstall reloads the registry: take a fresh environment.
60
+ env = api.Environment(odoo.registry(env.cr.dbname).cursor(), SUPERUSER_ID, {})
61
+
62
+ elif verb == 'owner':
63
+ owner = GIVEN.get('owner') or {}
64
+ admin = env.ref('base.user_admin')
65
+ admin.write({'login': owner['name'], 'password': owner['password'], 'email': owner['email']})
66
+ env.cr.commit()
67
+ print(' the administrator of the site is %s.' % admin.login)
68
+
69
+ elif verb == 'add':
70
+ for person in GIVEN.get('accounts') or []:
71
+ wanted, missing = [], []
72
+ for xmlid in ROLES.get(person['role'], []):
73
+ group = env.ref(xmlid, raise_if_not_found=False)
74
+ (wanted if group else missing).append(group.id if group else xmlid)
75
+ if person['role'] not in ROLES:
76
+ print(' %s: "%s" is not a role this knows (%s).' % (person['name'], person['role'], ', '.join(sorted(ROLES))))
77
+ continue
78
+ values = {'password': person['password'], groups_field: [(6, 0, wanted)], 'active': True}
79
+ user = Users.search([('login', '=', person['name'])], limit=1)
80
+ if user:
81
+ user.write(values)
82
+ state = 'was there: its groups and its password are set again'
83
+ else:
84
+ user = Users.create(dict(values, name=person['name'], login=person['name'], email=person['email']))
85
+ state = 'added'
86
+ env.cr.commit()
87
+ print(' %s %s (%s)%s.' % (person['name'], state, person['role'],
88
+ ', without %s (not installed)' % ', '.join(missing) if missing else ''))
89
+
90
+ elif verb == 'cancel':
91
+ for person in GIVEN.get('accounts') or []:
92
+ user = Users.search([('login', '=', person['name'])], limit=1)
93
+ if not user:
94
+ print(' %s is not there.' % person['name'])
95
+ continue
96
+ # An account the data of a module defines (the demo data has a portal user) is part of
97
+ # the site: deleting it breaks the next update of that module, so it is archived.
98
+ if env['ir.model.data'].search_count([('model', '=', 'res.users'), ('res_id', '=', user.id)]):
99
+ user.write({'active': False})
100
+ print(' %s is part of the data of the site, so it is archived instead of deleted.' % person['name'])
101
+ env.cr.commit()
102
+ continue
103
+ try:
104
+ with env.cr.savepoint():
105
+ user.unlink()
106
+ print(' %s deleted.' % person['name'])
107
+ except Exception:
108
+ # Records of the site point at the account: Odoo keeps it, so it is archived.
109
+ user.write({'active': False})
110
+ print(' %s has records the site keeps, so it is archived instead of deleted.' % person['name'])
111
+ env.cr.commit()
112
+
113
+ elif verb == 'list':
114
+ system = env.ref('base.group_system')
115
+ for user in Users.search([('share', 'in', [True, False])], order='share, login'):
116
+ if user.id == SUPERUSER_ID:
117
+ continue
118
+ kind = 'portal' if user.share else ('administrator' if system in user[groups_field] else 'internal')
119
+ print(' %-24s %-30s %-14s%s' % (user.login, user.email or '', kind, '' if user.active else ' (archived)'))
120
+
121
+ elif verb == 'apps':
122
+ for module in env['ir.module.module'].search([('state', '=', 'installed'), ('application', '=', True)], order='name'):
123
+ print(' %-28s %s' % (module.name, module.shortdesc))
124
+
125
+ else:
126
+ print('odoo-accounts.py: ODOO_ACCOUNTS_VERB is local, owner, add, cancel, list or apps, with commas.')
127
+
128
+ env.cr.commit()
129
+ env.cr.close()
@@ -0,0 +1,64 @@
1
+ Feature: The site answers and its accounts work
2
+ As the owner of the site
3
+ I want the front page, the login page and each default account to work
4
+ So that a build that came out broken is caught before anything else is tested
5
+
6
+ # Placed by the workspace's testing setup as a starting point: it is yours to change.
7
+ # The accounts are the default ones (cmd-tools-add-users.sh); a scenario logs in by a handle of
8
+ # the users registry in cucumber.js, so no password is written here. The apps named below are
9
+ # the ones the builder installs by default.
10
+
11
+ @critical
12
+ Scenario: The front page is served
13
+ Given I am an anonymous user
14
+ And I am on the homepage
15
+ Then the response status code should be 200
16
+ And I should be on a website page
17
+
18
+ @critical
19
+ Scenario: The login page is served with its form
20
+ Given I am on the login page
21
+ Then the response status code should be 200
22
+ And I should see the login form
23
+
24
+ Scenario: The administrator logs in and has every app
25
+ Given I am a logged in user with the "admin" user
26
+ Then I should be logged in as "administrator"
27
+ And I should be in the web client
28
+ And I should see the "Sales" app
29
+ And I should see the "Invoicing" app
30
+ And I should see the "Settings" app
31
+
32
+ Scenario: A salesperson has Sales and CRM, not Invoicing
33
+ Given I am a logged in user with the "salesperson" user
34
+ Then I should be logged in as "salesperson"
35
+ And I should see the "Sales" app
36
+ And I should see the "CRM" app
37
+ But I should not see the "Invoicing" app
38
+ And I should not see the "Settings" app
39
+
40
+ Scenario: An accountant has Invoicing, not Sales
41
+ Given I am a logged in user with the "accountant" user
42
+ Then I should be logged in as "accountant"
43
+ And I should see the "Invoicing" app
44
+ But I should not see the "Sales" app
45
+ And I should not see the "Settings" app
46
+
47
+ Scenario: An employee has no app of a role
48
+ Given I am a logged in user with the "employee" user
49
+ Then I should be logged in as "employee"
50
+ And I should be in the web client
51
+ But I should not see the "Sales" app
52
+ And I should not see the "Invoicing" app
53
+ And I should not see the "Settings" app
54
+
55
+ Scenario: A portal user never reaches the web client
56
+ Given I am a logged in user with the "portal" user
57
+ When I go to "/web"
58
+ Then I should be in the portal
59
+ And I should not be in the web client
60
+
61
+ Scenario: An anonymous visitor has no session
62
+ Given I am not logged in
63
+ And I am on the homepage
64
+ Then I should not be logged in