Skip to Content

PMIS Nextcloud

Beta License: LGPL-3 PMISuite/Beta Version: 18.0

Create and manage Nextcloud users and groups from Odoo, and import CardDAV contact data for review and linking to Odoo partners.

Features

The addon provides two independent integrations. A Nextcloud user account is identified by the partner's Nextcloud ID. A CardDAV contact link associates an address-book entry with an Odoo partner. Creating either link does not create the other.

Account administration

  • Explicit creation, verification of existing accounts, synchronization, metadata refresh, disabling, password reset, and local unlinking.

  • Fetch existing user accounts and review email, username, and display-name matches before pairing them with Odoo contacts, including manual choices.

  • Local-only partner creation, edits, archiving, and reactivation. Requested details and memberships are applied only by an explicit account action.

  • Stable remote usernames even when a partner's contact email changes.

  • Company-specific quota templates, unit validation, and normalized quotas.

  • Exact replacement of selected remote group memberships during synchronization.

  • Separate missing-account and retryable-error states, with recovery information retained after partial remote failures.

  • Cached quota totals, used space, free/use percentages, last login, and the original account metadata. Remote epoch timestamps are interpreted as UTC; the form displays dates using Odoo's normal timezone handling.

  • Manager-only generated passwords with configurable local expiration and optional template-based password-reset notifications.

  • Scheduled metadata refresh and local password cleanup.

  • Own-account password changes from Odoo's user menu, confirmed with the current Odoo password, without storing or emailing the new password.

CardDAV contact reconciliation

  • Discovery of address books through well-known CardDAV and DAV endpoints.

  • All-address-book or selected-HREF fetching, configurable request timeout, and separate credentials with fallback to the main connection.

  • Local indexing of vCard names, UIDs, email and phone lists, resource HREFs, ETags, address-book details, and last-seen timestamps.

  • ETag-based reuse of unchanged contacts; optional retention of raw vCard text, with retention changes respected even for unchanged contacts.

  • Company-scoped primary-email comparison with unique, missing, and ambiguous match proposals.

  • Manual review before creating Odoo partners, linking existing partners, ignoring proposals, or deactivating orphaned local links.

  • Persistent comparison counters and an application summary, with company consistency checks and one active contact link per partner.

  • Server-side fetch enablement, review-state and target validation, and stale creation checks before local application.

Configuration

Dependencies and connection

The module requires base, contacts, mail, and web, plus the Python dependency pyocclient in the Odoo instance environment.

  1. Open Settings → Nextcloud and enter the server URL, API login, and password. The API account must have the Nextcloud permissions needed for the user and group operations you intend to perform.

  2. Select Confirm and Login to validate the connection.

  3. Select Get Nextcloud Groups to import the groups available for partner assignment. Get Nextcloud Config retrieves server configuration.

The connection settings use database-wide configuration parameters. The quota template default is company-specific. Reset clears the stored connection and CardDAV/email parameters and requires reconfiguration. It does not remove partner mappings, indexed contacts, or remote data, and does not reset the company quota default or the separate password-retention parameter. The dialog's file-synchronization warning is inherited wording, not an implemented file operation in this addon.

Root Directory and Use Public URLs are stored settings; this addon does not implement a file synchronization or public-share workflow using them.

CardDAV

Enable CardDAV Enabled and configure the DAV endpoint, for example https://cloud.example.com/remote.php/dav. Set separate CardDAV credentials when needed; otherwise the client uses the main connection credentials. CardDAV Timeout defaults to 20 seconds and is used for both address-book discovery and contact fetching. Store Raw vCard is off by default; when enabled it retains source contact data. When it is off, fetching clears previously retained raw text for each contact in the fetched scope, including contacts with unchanged ETags. Records outside that scope retain their existing text. Enabling it fetches raw text for cached contacts that lack it. Missing ETags always trigger a fresh vCard request.

CardDAV Enabled gates address-book discovery and contact fetching on the server, including direct wizard/RPC calls. Enable it explicitly before importing; unset or disabled values block fetching even when credentials are configured. The switch leaves Contacts menus and local review/application available, and does not affect the independent Nextcloud account actions.

DAV requests and redirects must stay on the configured URL's origin (scheme, host, and port). Configure the final canonical DAV URL if a proxy redirects between origins. Credentials are never forwarded across that boundary. Malformed XML, document type declarations, unexpected response documents, and failed DAV resource statuses abort fetching before orphan proposals are rebuilt. Missing optional properties such as ETags are allowed and fetched afresh.

Quota templates

Quota values accept B, KB, MB, GB, or TB, case-insensitively, such as 100MB, 1GB, or 0.5TB. Missing or unsupported units are rejected; 1024MB is normalized to 1GB.

Users in the Access Rights administration group (base.group_erp_manager) can manage nextcloud.quota.template records. The addon supplies the Nextcloud Quota Templates window action but no dedicated menu. Administrators can access that action in developer mode or manage the template through Default quota template in Settings.

Select Default quota template in Settings → Nextcloud for the current company. On partner creation, a missing or empty quota uses that company's default, falling back to the current company for a partner without a company. This only supplies a local default and never provisions a remote user. Changing the default does not update existing partners. Without a template or an explicit quota, account synchronization sends the fallback quota 100MB. The validator accepts nonnegative decimal quantities and Nextcloud's none (unlimited) and default quota keywords. unlimited is normalized to none.

Access and company scope

  • Settings are reached through the normal Odoo administration interface. Connection, CardDAV, email, and retention settings are database-wide.

  • Account actions require Access Rights administration (base.group_erp_manager), partner write access, and access to the partner's company. Button visibility is not the security boundary.

  • Password and expiration fields are restricted to that group in the ORM. Ordinary internal users can read quota templates; administrators can modify them. The company default is stored on res.company.

  • Active internal users can change only their own linked Nextcloud password, after confirming their Odoo password. The server derives the account from the current user's partner and enforces selected-company access; callers cannot provide another user's ID. Portal and public users are denied.

  • Internal users (base.group_user) have CRUD access to imported groups, CardDAV contacts, links, runs, review lines, and both wizards, subject to company rules and ordinary partner permissions. CardDAV operations are not limited to the account-administration group.

  • The seven CardDAV models allow records belonging to selected companies and shared records without a company. New cross-company relations are rejected. Groups and connection settings are shared across the database.

  • Creating a local group outside the import context also attempts to create it remotely, and rejects an existing remote name. Importing groups only adds unknown remote IDs; it does not delete local groups missing from the server. Deleting a local group does not delete the remote group.

Scheduled actions

On a new installation, Get Nextcloud User Data is active every ten minutes as the Odoo root user. Its default code selects all companies and refreshes linked partners, including archived ones, except accounts already marked Missing or Inaccessible. Disabled, pending, and error accounts remain eligible. The job reads metadata; it never provisions users or applies pending changes. Custom cron users must meet the account-action access requirements.

Expire Stored Nextcloud Passwords is active hourly as the root user. It clears only expired local credentials and their deadlines, including archived partners. Both cron records are noupdate; deployed schedule customizations are preserved. Review scheduling under Odoo's Scheduled Actions in developer mode.

Usage

User accounts

To pair existing accounts in bulk, open Contacts → Nextcloud → Fetch and Pair Accounts as an Access Rights administrator with contact-write access. Select the company and optionally include archived contacts, then select Fetch Accounts. The API login must be allowed to list users and read their details. Only accounts returned by that login are shown; CardDAV configuration is not required. The results open in a full-page list with search fields for account username, display name, email, and Odoo contact, plus filters for matching status and accounts selected to pair. Selections remain marked when you change filters; Pair Selected Accounts processes every marked proposal in the session. For an account with No Match, use Create and Pair on its row to create an Odoo contact in the selected company and immediately link the account. The contact uses the Nextcloud display name (or account username) and email. Other proposals and selections remain available for review. If pairing fails, the new contact is not retained.

Proposals combine exact normalized emails with complete contact-name matches against Nextcloud account usernames and display names. Name matching ignores case and extra whitespace, so different emails can still produce a name match. Conflicting evidence and repeated names show Multiple Candidates; no candidate is silently preferred. Review the candidates and choose the intended Odoo Contact, including a manual choice when no match exists. Tick Pair for each desired mapping and select Pair Selected Accounts. All proposals start unselected. Shared contacts and contacts in the selected company are eligible; inaccessible contacts are never proposed. Review sessions and their fetched account details are restricted to their creator and allowed companies.

Pairing rechecks each selected remote account and applies local mappings atomically. It never creates accounts or changes remote details, passwords, quotas, groups, or enabled status. Pairing imports the current remote quota and group memberships into the Odoo contact. Groups are reused by Nextcloud ID, or paired with an unlinked local group of the same name; missing groups are created only in Odoo. Duplicate local group matches must be resolved before pairing. The quota uses the API's quota limit, never the storage total or free space, and preserves exact byte limits and unlimited quotas. Missing or unknown quota information blocks pairing rather than applying a fallback quota. Quota templates are not created or changed.

Existing mappings are preserved. An account can belong to only one Odoo contact, including archived contacts. Unavailable accounts and already paired accounts are shown separately. Successful pairing sets Linked, or Disabled for a disabled remote account, without requesting synchronization. Fetch Again discards selections and refreshes proposals. An already paired account in the selected scope can be selected to refresh its local groups and quota. Pairing re-reads these settings before applying them.

Upgrades reject duplicate existing Nextcloud IDs before adding the uniqueness constraint. Resolve duplicates by retaining the intended contact mapping and unlinking the other contacts locally; remote accounts remain intact.

  1. Open an active partner with an email address and select the Nextcloud tab.

  2. Set the quota and imported groups, then save. Saving never calls Nextcloud.

  3. As an Access Rights administrator, select Create Account to create an account using the email as its username. To link an existing account, enter its exact Nextcloud ID and select Link Existing Account. Linking verifies the account and imports its current quota and group memberships into Odoo without changing the remote account.

  4. Select Synchronize Account to apply saved details, quota, and groups. This replaces remote group membership with the selected groups, including removing all memberships when the selection is empty. It also enables a disabled account. Edits to linked partners show Pending Synchronization.

  5. Select Refresh NC Account to read account metadata. Refreshing preserves pending synchronization. Review quota usage and last login on the partner.

Archiving and reactivating a partner are local changes. Select Disable Account explicitly when access should be revoked. Unlink Locally removes the local mapping and cached metadata without deleting or disabling the remote account. Changing a linked partner's email updates its contact email on synchronization; the existing Nextcloud username remains stable.

An OCS not-found user response marks an account Missing or Inaccessible, clears cached metadata and the stored password, and retains its ID for recovery. The recognized OCS status codes are 404 and 998; other exceptions and empty or nonmapping responses are treated as retryable errors. Scheduled refreshes skip these accounts. Restore the account or API access and refresh manually, or unlink locally before explicitly creating a replacement. Missing accounts are never automatically recreated. Permission restrictions can also hide an account; check API permissions before concluding it was deleted.

Account states distinguish Not Linked, Pending Synchronization, Linked, Disabled, Missing or Inaccessible, and Connection or Operation Error. Editing a mapped partner's name, email, phone, website, active flag, quota, or groups sets the pending flag. Refresh reads the remote enabled state without clearing that flag. Editing a missing account keeps it missing until a successful manual verification.

Synchronization sends name as display name, email, phone, website, and quota. Blank phone and website values clear their remote attributes. Account creation refuses to take over an existing username: explicitly enter the ID and link it. An archived partner or one without an email cannot be created/synchronized. Disabling and unlinking remain available for archived mapped partners.

Connection and operation failures retain the mapping and report an error for retry. Partial remote writes cannot be rolled back by Odoo. When creation succeeds but a later step fails, the mapping and actual initial password remain available; retry updates that account. UI account actions return a warning notification on these persisted failures; automation must check the Boolean outcome. Passwords are generated only for creation or explicit reset, and synchronizing an existing user preserves its stored password and expiration deadline. Creation uses a URL-safe random token. A partial failure may retain the password in the manager-only field even if the form's cached-metadata section is still hidden; refresh or retry before relying on the normal form display.

Chatter records explicit local unlinking, disabling, and password-reset actions, without including the generated password. It is not a transaction log of all remote writes.

Password resets

Select Reset NC Password on a partner with a Nextcloud username. The form shows this button to the Access Rights administration group. The action sets a new remote password and writes it to nextcloud_initial_password.

Account actions enforce the Access Rights administration group, partner write access, and the selected company boundary on the server. Password field access is restricted to that group in the ORM.

Password retention (hours) controls how long newly generated or reset passwords remain on the partner. New installations default to 24 hours. The hourly Expire Stored Nextcloud Passwords scheduled action clears local passwords whose deadline has passed, including those on archived partners. It never changes the remote password. The deadline appears beside the password. An expired value can remain visible until the next cleanup run.

Zero retains passwords indefinitely. Upgrades preserve that legacy policy and existing passwords; administrators can enable expiry in Settings. Changing the setting applies to subsequent creation and password-reset actions. It does not retroactively erase credentials, and ordinary synchronization does not extend the retention deadline.

Optionally enable Send password reset email and choose a Password reset email template in Settings. The template receives the password through ctx['password']. Check recipients and template output before enabling this option; an email containing the password can retain it beyond the reset action.

Select an existing partner email template or create one before enabling delivery. The password-reset template XML present in the source tree is not listed in the manifest, so installation does not load it automatically.

Change your own Nextcloud password

  1. Open your Odoo user menu and select Change Nextcloud Password.

  2. Check the linked Nextcloud account shown in the dialog.

  3. Enter your current Odoo password, a new Nextcloud password of 12 to 1024 characters, and its confirmation. Select Change Password.

Your Odoo password stays unchanged. The new password is sent directly to the linked Nextcloud account; it is neither stored in Odoo nor emailed. A successful change clears any old administrator-generated password and its retention deadline, and posts a credential-free audit message on your partner. The dialog clears its password inputs on success, failure, and closure. Concurrent duplicate submissions are blocked while the request is pending.

You do not need the old Nextcloud password, but must know your current Odoo password. Odoo's authentication rate limit applies. The partner must be active and mapped to an account that is not marked missing or disabled; ask an administrator to restore or link such accounts first. Nextcloud's own password policies still apply. This is an Odoo-authenticated password change, not a Nextcloud-hosted forgot-password or email recovery flow.

Upgrading existing installations

Version 18.0.1.2.0 includes migration scripts for existing installations. The upgrade initializes workflow status for linked accounts, including archived partners, using cached metadata only. Existing usernames, quotas, groups, passwords, and metadata are preserved. No Nextcloud calls are made by migration. Existing missing, error, or pending workflow states are not overwritten on retry.

The refresh cron preserves its active flag, interval, assigned user, and other deployment settings. Only the original default code is updated to refresh all companies; customized cron code is preserved. Future module updates no longer reset the cron's settings.

The same upgrade adds password retention and company access rules. It retains existing passwords without deadlines and preserves an already configured retention setting. Stored company ownership on links and review lines is derived from their existing contacts, partners, and runs without changing those relations. Records without a company remain shared for compatibility.

The intended workflow change is that saving or archiving a partner no longer performs remote writes. Administrators use the explicit account actions instead. Existing automation can still call send_nextcloud_user(), set_nextcloud_group(), and get_nextcloud_user(); account operations require the administration group and applicable company access, and callers must check their Boolean results for remote failures. A missing linked account is never recreated implicitly. Synchronization updates the existing Nextcloud ID even when the partner's email changes.

CardDAV contact review

  1. Open Contacts → Nextcloud → Sync Nextcloud Contacts.

  2. Choose All address books, or Selected and use Fetch Addressbooks to populate Select Addressbook. Choosing a discovered book copies its HREF into Addressbook HREF; you can also enter that HREF manually. Discovery fills the first HREF only if the field is empty. Selected scope requires an HREF before Fetch & Compare can run.

  3. Review the proposals and ambiguous primary-email matches in Nextcloud Sync Review.

  4. Choose Create Odoo, Link Existing, Ignore, or None for contact proposals. For an ambiguous match, explicitly choose the intended partner before selecting Link Existing. Review Orphan Odoo Links and select Keep or Unlink; proposed orphan actions default to Unlink.

  5. Select Apply Selected Actions, review the proposal counts, and choose whether to Create missing Odoo contacts and Deactivate orphan Nextcloud links. Both checkboxes default to enabled; turn them off to suppress those action categories. Then select Apply.

The comparison uses the first vCard email, lowercased and stripped, against Odoo partner emails with case-insensitive exact matching. Secondary emails, phone numbers, names, and UIDs do not participate in partner matching. A unique match proposes linking only if that partner lacks an active contact link; no match proposes creation; multiple matches require manual selection. A contact without an email has no proposed action.

Include Inactive Partners includes archived partners in email matching. Without it, archived partners are excluded even if the caller disables Odoo's normal active_test context. Linking an archived partner does not reactivate it.

Orphan detection considers active links in the run's company and shared links. A fetched UID or resource HREF keeps a link present only within the same address book. Identical UIDs in other books do not conceal missing contacts. All-book fetches consider links only in books actually discovered and fetched; absent or inaccessible books are left alone. Selected-book runs consider only links with that address-book HREF. Absence within a fetched book is not proof of deletion: changed DAV permissions can still hide individual contacts.

Applying proposals creates Odoo partners or local links. A newly created partner receives name, primary email, the first imported phone number, the run's company, and person type. Additional phone numbers and other vCard attributes are not copied. Existing partner details are never updated by a link action. Unlinking an orphan deactivates the local link without deleting the partner or remote contact. The workflow does not push contact edits back to CardDAV. Creating a partner here applies local quota defaults without provisioning a Nextcloud account.

Contacts, links, runs, review lines, and both wizards enforce access to the user's selected companies. Company consistency checks reject new links and review lines that mix company-owned records; shared Odoo partners remain usable. Matching and orphan detection stay in the synchronization run's company even when an administrator has selected multiple companies.

Re-fetch & Compare replaces the run's previous proposals and counters, so manual action selections must be reviewed again. Applying marks the run Done and writes the created/linked/unlinked counts to Log; it does not change the imported contact's comparison status to a linked status. The server accepts application only in Review, rejects repeated application, and rolls back all local application effects on failure. Link Existing requires a writable partner with a matching email in the run's company or a shared partner; ambiguous proposals require one of their proposed candidates. Archived targets require Include Inactive Partners. Completed runs cannot be fetched again; start a new run for another import. Creation actions are checked again against current partners and against other creation proposals in the same run. If a matching partner has appeared since comparison, or multiple selected proposals share an email, application is rejected before creating anything. Re-fetch and compare to resolve stale proposals; choose only one creation action per email for duplicated source contacts.

Browse indexed records at Contacts → Nextcloud → Nextcloud Contacts and local mappings at Contacts → Nextcloud → Nextcloud Contact Links. Contact lists support Missing in Odoo, Ambiguous, Matched, and Last Seen Today filters, with grouping by address book or state. Contact forms show email and phone JSON lists and optional raw vCard text; direct contact creation is disabled in these views. Link records can retain notes, identity fields, and inactive history. The partner model also provides an action and computed fields for its active CardDAV links; the supplied partner form does not add a dedicated links button.

TODO

No additional implementation TODOs are currently tracked. Remaining integration constraints are listed under Known limitations.

Data model notes

  • res.partner stores the username, requested quota, group assignments, cached response and timestamp, account state/error, pending flag, generated password, and cleanup deadline. Mapping, cache, password, and workflow fields are not copied when duplicating a partner. Usage and last-login displays are computed from the cache; disk-space amounts are raw byte values.

  • nextcloud.groups stores imported IDs, display names, and tag colors.

  • nextcloud.quota.template stores a required quota and a company-specific name; duplicate names in the same company are rejected.

  • res.company.nextcloud_default_quota_template_id defines the local partner-creation default.

  • nextcloud.contact stores fetched CardDAV contact data; nextcloud.contact.link connects it to an Odoo partner.

  • nextcloud.contact.sync.run and its contact/orphan review lines retain comparison proposals and application results. Runs are ordered newest first. A nonempty ETag match updates last-seen time without refetching the vCard, unless raw-text retention is enabled and its cached text is missing.

  • Contact links derive company ownership from their indexed contact, falling back to the partner. One active link per partner is enforced across companies; inactive links may be retained as history.

Integration API notes

Existing code may explicitly call send_nextcloud_user() to create/sync, set_nextcloud_group() for group-only changes, and get_nextcloud_user() for metadata refresh. Empty partner recordsets on the last method mean scheduled refresh of eligible accounts, not a no-op. Group-only synchronization verifies the account but does not clear unrelated pending changes. Account UI methods return Odoo notification actions; password reset can raise UserError on invalid prerequisites or a failed password write. Normal account operations enforce server-side administration/company checks even when called outside the UI.

The CardDAV wizard calls the run synchronously. The context flag test_queue_job_no_delay skips the fetch for tests; no queue-job integration is implemented by this addon. Discovered address books are passed through the reopened wizard's context to its selection field. The run's stored create_missing_odoo and unlink_orphan_links fields do not drive application; the apply wizard passes its own Boolean choices.

res.users.get_own_nextcloud_account() returns the current user's mapped username. action_change_own_nextcloud_password(odoo_password, new_password, confirmation) changes only that account and returns True on success; invalid credentials or prerequisites and remote failures raise errors. Neither method accepts a target user or partner. Only clearing the stale manager-only password and posting the audit message use narrowly scoped elevated access.

The legacy models/json_field.py helper remains in the source tree but is not registered by normal model imports. Current forms use native Odoo JSON fields; the backend web assets implement only the own-password dialog.

Known limitations

  • User provisioning depends on Nextcloud/ownCloud API compatibility through pyocclient.

  • Password notification emails can retain a password beyond local cleanup. Existing installations keep indefinite retention until an administrator enables expiry.

  • Fetching and linking contacts does not implement bidirectional contact synchronization, a full vCard specification parser, or automatic recurring CardDAV imports. The parser handles unfolded FN/UID/EMAIL/TEL properties, property groups, standard text escapes, and mailto/tel URI prefixes. It also decodes legacy quoted-printable/base64 text with declared charsets and falls back to structured N names when FN is absent. It does not map postal addresses, organizations, photographs, and all vCard parameters.

  • Account operations and contact imports are synchronous and depend on remote response time. External writes are not distributed transactions.

  • A generated password is restricted by Odoo access rights, not encrypted by this addon. Retention cleanup cannot erase copies in email, backups, or external systems. Own-account changes require an Odoo password; users with only external authentication must obtain one through their Odoo administrator. Nextcloud-hosted or email-based self-service recovery remains outside scope.

  • Orphan proposals depend on the completeness of the fetched scope and DAV permissions. Explicit DAV errors abort fetching, but a successful server response can still silently omit inaccessible contacts. Review orphan proposals before deactivating links. Creation checks reject stale proposals and repeated emails within a run; simultaneous applications of separate runs are not protected by a database-wide email uniqueness rule.

  • Third-party, server, proxy, and mail logs are outside this module's privacy controls. Its own operation logs omit account names, private URLs, remote exception text, and user metadata.

Validation

The tests cover client integration with mocked responses, quotas, partner lifecycle, missing/unavailable accounts, permission/company boundaries, partial creation retries, password reset/cleanup, migrations, CardDAV parsing/discovery, and contact review/apply choices. Remote clients are replaced by synthetic responses; these checks do not certify a particular live server deployment. Own-password tests verify Odoo credentials, unchanged Odoo passwords, fixed own-account targeting, portal/inactive/company denials, input validation, API fallbacks, remote failures, and removal of stale cached credentials. The HOOT suite tagged pmis_nextcloud_password exercises masked inputs, focus, submission, errors, duplicate submissions, credential cleanup, and the user-menu account lookup using mocked RPC services. Additional regressions cover CardDAV enablement and timeout validation, optional archived matching, repeat application, stale creation and ambiguous targets, atomic application rollback, raw-text retention changes, absent ETags, and phone import. Orphan tests cover undiscovered books and cross-book UID collisions. Database-free client tests cover grouped properties, text escapes, legacy text decoding, structured-name fallback, and empty-endpoint discovery retries. Tests use one test_<source_filename>.py file per defining Python class file, including test_abstract_owncloud_client.py. Shared fixtures and synthetic clients live in tests/conftest.py. Migration tests remain in test_pre_migration.py and test_post_migration.py; installation checks target Odoo's ir.module.module in test_ir_module_module.py. Database-backed checks require an authorized disposable database.

From the configured PMIVerse workspace, use a fresh database name:

/srv/pmiverse/_pmiconfig/scripts/test/run_pytest_addon.sh \
  -a /srv/pmiverse/_pmisuite18/repos/pmiverse/pmis-beta/pmis_nextcloud/tests \
  -d test_pmis_nextcloud_unique -- -q

For statement and branch coverage, use the repository coverage runner:

/srv/pmiverse/_pmiconfig/scripts/test/run_pytest_repo.sh \
  --addons /srv/pmiverse/_pmisuite18/repos/pmiverse/pmis-beta/pmis_nextcloud \
  --db-prefix test_pmis_nextcloud_coverage_unique_ --parallel 1 -- \
  -q --cov-branch --cov-fail-under=100

The runner creates/drops its disposable database and can write suite-level logs and filestore data. Do not reuse production database names. Static quality settings are defined in the owning repository's pyproject.toml; direct Ruff, pylint-odoo, XML parsing, and RST rendering complement runtime tests.

Bug Tracker

Bugs are tracked on PMISuite Repository Issues. Before opening a new issue, check whether it has already been reported. Include the module and Odoo versions, steps to reproduce, and expected and actual results. Use synthetic examples and redact sensitive information.

Credits

Authors

Contributors

  • Matjaž Mozetič

  • Carlo Vettore

Maintainers

LUXIM MATMOZ

Current maintainer:

sysadminmatmoz LUXIM

Luxim is an independent R&D and deployment company focused on solving complex problems in the Odoo ecosystem.

Odoo Community Association

Luxim is an active member of OCA (Odoo Community Association).