diff --git a/.circleci/config.yml b/.circleci/config.yml index 0dcd5f9..aec59b2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,47 +1,60 @@ version: 2.1 orbs: - qqq-orb: kingsrook/qqq-orb@0.3.8 + qqq-orb: kingsrook/qqq-orb@0.6.9 + +commands: + configure-package-install: + steps: + - run: + name: Keep package installation unattended + command: | + # These build machines are discarded after the job. + sudo install -d /etc/needrestart/conf.d + printf '%s\n' '$nrconf{restart} = "l";' | sudo tee /etc/needrestart/conf.d/99-qqq-ci.conf >/dev/null workflows: + test_only: + jobs: + - qqq-orb/mvn_test_only: + pre-steps: + - configure-package-install + context: [qqq-maven-registry-credentials] + filters: + branches: + ignore: /(develop|release\/.*)/ - test_only: - jobs: - - qqq-orb/mvn_test_only: - context: [ qqq-maven-registry-credentials ] - filters: - branches: - ignore: /(develop|main|release/.*|integration.*)/ - tags: - only: [] + publish_snapshot: + jobs: + - qqq-orb/mvn_publish: + pre-steps: + - configure-package-install + context: [qqq-maven-registry-credentials] + branch_type: snapshot + filters: + branches: + only: [develop] - publish_snapshot: - jobs: - - qqq-orb/mvn_publish: - context: [ qqq-maven-registry-credentials ] - branch_type: snapshot - filters: - branches: - only: - - develop + publish_release_candidate: + jobs: + - qqq-orb/mvn_publish: + pre-steps: + - configure-package-install + context: [qqq-maven-registry-credentials] + branch_type: release_candidate + filters: + branches: + only: [/release\/.*/] - publish_release_candidate: - jobs: - - qqq-orb/mvn_publish: - context: [ qqq-maven-registry-credentials ] - branch_type: release_candidate - filters: - branches: - only: - - /release\/.*/ - - publish_release: - jobs: - - qqq-orb/mvn_publish: - context: [ qqq-maven-registry-credentials ] - branch_type: release - filters: - branches: - only: [ main ] - tags: - only: [ /^v\d+\.\d+\.\d+$/ ] + publish_release: + jobs: + - qqq-orb/mvn_publish: + pre-steps: + - configure-package-install + context: [qqq-maven-registry-credentials] + branch_type: release + filters: + branches: + ignore: /.*/ + tags: + only: [/^v\d+\.\d+\.\d+$/] diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dc513d7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +mvnw text eol=lf +mvnw.cmd text eol=crlf diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..c0bcafe --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,3 @@ +wrapperVersion=3.3.4 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..5286020 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,15 @@ +# QBit CRM + +CRM metadata, processes and widgets for QQQ. P1 upgrades the platform; later phases are defined in the 0.2.0 design. + +## Build + +Use Java 21 and the Maven wrapper: `./mvnw -q verify` runs checkstyle, tests and JaCoCo (70% instructions, 90% classes). Parent: `qbit-build-parent:2.1.2`; default-active `qqq-snapshot` BOM: `4.1.0-RC.6`. Architecture guardrails and strict UI API routes stay enabled. + +## Conventions + +- Entry point: `CrmQBitProducer`, with package-discovered metadata producers. +- Table, join, widget and process names use `crm_` snake_case. Database columns use snake_case; Java fields stay camelCase. +- Allman braces, 3-space indentation, `return (x);`, fluent setters and Javadoc flower-box banners. +- New source files carry the Apache 2.0 license header. +- Keep changes scoped and run verify before committing. Do not push without authorization. diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..907444b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +## Unreleased / 0.2.0 + +- Upgrade to Java 21, QQQ 4.1.0-RC.6 and qbit-build-parent 2.1.2. +- Add Maven wrapper, CI configuration, architecture guardrails and coverage gates. +- Rename tables, joins, widgets and CRM processes to `crm_` snake_case, with inferred snake_case SQL columns. +- Remove bespoke tag, attachment and audit tables, bulk tag processes and unused namespace/prefix configuration. +- Use core FIELD-level auditing on contacts, companies, deals and activities. +- Apply CRM, management and admin permission rules and source-QBit metadata, including an RC.6 widget provenance adapter. +- Ship PostgreSQL DDL, 33 Liquibase changesets, and H2 persistence and schema tests. 0.2.0 is a fresh install; there is no upgrade path from 0.1.0. +- Correct installation instructions and document the existing P1 behavior and remaining limitations. diff --git a/README.md b/README.md index fb5830f..ab675ff 100644 --- a/README.md +++ b/README.md @@ -1,485 +1,140 @@ -# QBit: CRM +# QBit CRM -[![Version](https://img.shields.io/badge/version-0.1.0-blue.svg)](https://github.com/QRun-IO/qbit-crm) -[![License](https://img.shields.io/badge/license-Apache%202.0-green.svg)](https://www.apache.org/licenses/LICENSE-2.0) -[![Java](https://img.shields.io/badge/java-17+-blue.svg)](https://adoptium.net/) +**0.2.0-SNAPSHOT — unreleased, P1 Platform.** CRM tables, processes and widgets for QQQ applications. This phase upgrades the build, names, permissions, audit integration and database schema. It does not complete the later 0.2.0 product phases. -> **Customer Relationship Management for QQQ Applications - Activity-Centric, Pipeline-Driven** +## Build and verification -This QBit provides a complete CRM system for QQQ applications, covering contact and company management, deal pipeline tracking, activity logging, email tracking, product catalog, lead scoring, assignment automation, website form capture, mailing list subscriptions, and reporting. +Use **Java 21** and the included Maven wrapper (**Maven 3.9.11**). The build uses `com.kingsrook:qbit-build-parent:2.1.2` and a default-active `qqq-snapshot` profile importing `qqq-bom-pom:4.1.0-RC.6`. -## Core Capabilities - -- **Contact & Company Management**: Full lifecycle tracking with tagging, segmentation, and duplicate detection -- **Deal Pipeline**: Configurable multi-pipeline stages with probability weighting, rot/aging detection, and stage-gating rules -- **Activity Tracking**: Unified activity table for calls, emails, meetings, notes, and tasks with per-record timelines -- **Email Integration**: Tracked email sending, open/click/bounce detection, templates with merge fields -- **Email Sequences**: Multi-step automated outreach with configurable send windows and failure handling -- **Lead Scoring**: Rule-based scoring with dot-notation field paths and time-decay operators -- **Assignment Automation**: Round-robin, least-active, and rule-based auto-assignment -- **Website Forms**: Capture web form submissions with UTM tracking and lead conversion -- **Mailing Lists**: Newsletter and subscription management independent of sales sequences -- **GDPR Compliance**: Consent tracking, right-to-erasure via anonymization (not deletion) -- **Multi-Currency**: Exchange rate table with converted amounts for accurate pipeline reporting -- **Immutable Audit Log**: Field-level change tracking with anonymization support for GDPR -- **14 Dashboard Widgets**: Pipeline summary, forecast, leaderboard, conversion rates, win rate, activity feed, and more - -## Open Source & Full Control - -QBit CRM is 100% open source under Apache 2.0. All data stays in your systems. No external CRM services required. - -## Architecture - -### Design Principles - -1. **Activity-centric**: A unified `crm_activity` table is the heart of the system. Every interaction (calls, emails, meetings, notes, tasks) is an activity linked to contacts, companies, and deals. One table to query, one timeline per record. - -2. **Pipeline-driven**: Deals move through configurable pipeline stages. Each stage has probability weighting, rot thresholds, and optional required-field gating. Stage transitions are first-class events captured in `crm_deal_stage_history` for reliable analytics. - -3. **Perpetual activity log**: The `crm_audit_log` table is immutable and append-only. Every meaningful change is recorded with field-level old/new values. For GDPR, PII is anonymized in-place rather than deleted. - -### Technology Stack - -- **Java 17+** with QQQ backend modules -- **QQQ Framework**: Entities, processes, widgets, permissions, API layer -- **Database**: RDBMS through QQQ's backend abstraction -- **MemoryRecordStore**: Full test suite runs in-memory (no database required) - -### Module Organization - -``` -qbit-crm/ - src/main/java/com/kingsrook/qbits/crm/ - CrmQBitConfig.java -- Configuration (backend, security, companion QBits) - CrmQBitProducer.java -- Gen 2 QBitMetaDataProducer (auto-discovers all entities) - core/ -- Contacts, Companies, Tags, Attachments, Forms, Email Lists - deals/ -- Deals, Pipelines, Stages, Products, Line Items, Stage History - activities/ -- Activities, Activity Types, Outcomes, Participants - email/ -- Email Messages, Templates, Sequences, Enrollments - scoring/ -- Lead Score Rules, Assignment Rules, Sales Goals - audit/ -- Immutable audit log + CrmAuditLogCustomizer - sync/ -- External system mapping, Currency management - widgets/ -- 14 dashboard widgets (producers + renderers) +```sh +./mvnw -q verify +# Windows PowerShell: +./mvnw.cmd -q verify +# If dependencies are already cached and network resolution is unavailable: +./mvnw.cmd -o -q verify ``` -## Getting Started +Verification runs Checkstyle on production and test sources, architecture guardrails (including strict UI API routes), JUnit tests and JaCoCo 0.8.15. Coverage gates are 70% instructions and 90% classes. The current suite runs **372 tests**, with no failures or skips, including four H2 integration tests. Tests use H2 2.3.232 and AssertJ 3.27.7. CircleCI uses `kingsrook/qqq-orb@0.6.9`. -### Prerequisites +The H2 tests execute the shipped PostgreSQL DDL in PostgreSQL mode. They verify all 33 tables and 395 columns, the 21 declared unique keys, relationship indexes, seven persisted entity types, duplicate list-member rejection and DDL/changelog parity. They do not replace deployment verification against the host's PostgreSQL installation. -- **Java 17+** -- **Maven 3.8+** -- **A QQQ Application** with an RDBMS backend (PostgreSQL, MySQL, H2, etc.) -- **QQQ Maven Registry** access (for resolving the dependency) +## Install in a host application -### Step 1: Add the Maven dependency +1. Build/install this unreleased snapshot with `./mvnw install`, or resolve the same artifact from your configured snapshot repository. The dependency version is explicit; do not assume the QQQ BOM manages this QBit. ```xml - com.kingsrook.qbits - qbit-crm - 0.1.0-SNAPSHOT + com.kingsrook.qbits + qbit-crm + 0.2.0-SNAPSHOT ``` -If you are using the QQQ BOM POM, the version is managed for you: -```xml - - - - com.kingsrook.qqq - qqq-bom-pom - ${qqq.version} - pom - import - - - -``` +2. Align the host with QQQ **4.1.0-RC.6**. For a new database, apply [the reference PostgreSQL DDL](docs/ddl/postgres.sql), or include the packaged Liquibase formatted SQL at `db/liquibase/qbit-crm/crm.changelog.sql`. Choose one installation path. The Java producer does not create the schema. -### Step 2: Configure and produce the QBit - -In your application's metadata setup class (where you build your `QInstance`), add the CRM QBit. The `defaultBackendNameForTables` must match a backend you have already registered with your QInstance (typically your RDBMS backend). +3. Register the host backend and authentication, then produce and add the CRM metadata: ```java import com.kingsrook.qbits.crm.CrmQBitConfig; import com.kingsrook.qbits.crm.CrmQBitProducer; -import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerMultiOutput; - -// In your QInstance setup method: -public void defineQInstance(QInstance qInstance) -{ - // ... your existing backend, auth, and app setup ... - - /////////////////////////////// - // configure and produce CRM // - /////////////////////////////// - CrmQBitConfig crmConfig = new CrmQBitConfig() - .withDefaultBackendNameForTables("rdbms"); // must match a registered backend name - - CrmQBitProducer crmProducer = new CrmQBitProducer() - .withQBitConfig(crmConfig); - - MetaDataProducerMultiOutput crmOutput = crmProducer.produce(qInstance); - crmOutput.addSelfToInstance(qInstance); -} -``` - -### Step 3: Create the database tables - -The QBit defines 39 tables. On first run against a new database, you need to create the schema. QQQ can auto-create tables if your backend supports it, or you can generate DDL from the entity metadata. - -For **development/testing** with H2 or auto-DDL: -```java -// QQQ will auto-create tables in memory backends. -// For RDBMS with auto-DDL enabled, tables are created on startup. -``` - -For **production** with PostgreSQL/MySQL, generate migration scripts from the entity field definitions. Each entity class documents its table name (e.g., `crmContact`, `crmCompany`, `crmDeal`) and all field types. Column names in the database are `snake_case` versions of the Java `camelCase` field names (e.g., `firstName` -> `first_name`). - -### Step 4: Add CRM to your app navigation - -```java -import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData; - -QAppMetaData app = new QAppMetaData() - .withName("myApp") - .withLabel("My Application") - .withSections(List.of( - CrmQBitProducer.produceAppSection(), - // ... your other app sections ... - )); -qInstance.addApp(app); -``` - -This adds a "CRM" navigation section to the QQQ Material Dashboard with links to all CRM tables. - -### Step 5 (optional): Seed reference data - -The CRM works without seed data, but you'll want to populate the configuration tables before users start working: - -- **`crmLifecycleStage`**: Lead, Marketing Qualified, Sales Qualified, Opportunity, Customer, Evangelist -- **`crmLeadSource`**: Website, Referral, Cold Call, Trade Show, Social Media, Advertisement, Partner -- **`crmIndustry`**: Technology, Healthcare, Finance, Manufacturing, Retail, etc. -- **`crmActivityType`**: Call, Email, Meeting, Note, Task (with `isSystem=true`) -- **`crmActivityOutcome`**: Connected, Left Voicemail, No Answer (for Call type); Completed, No Show, Rescheduled (for Meeting type) -- **`crmPipeline`** + **`crmPipelineStage`**: At minimum one pipeline with stages (Prospecting, Qualification, Proposal, Negotiation, Closed Won, Closed Lost) -- **`crmContactRole`**: Decision Maker, Influencer, Champion, Budget Holder, End User, Evaluator -- **`crmWinLossReason`**: Better Fit (WIN), Price (WIN), Lost to Competitor (LOSS), No Budget (LOSS), etc. -- **`crmCurrency`**: At minimum USD with `isBaseCurrency=true` and `exchangeRateToBase=1.0` - -You can insert these via QQQ's `InsertAction` in an application startup process, or directly via SQL. - -### Step 6 (optional): Multi-tenant security - -For SaaS or multi-tenant deployments where each client's CRM data must be isolated: - -```java -import com.kingsrook.qqq.backend.core.model.metadata.security.RecordSecurityLock; +// The host has already registered the backend named "rdbms". CrmQBitConfig crmConfig = new CrmQBitConfig() - .withDefaultBackendNameForTables("rdbms") - .withRecordSecurityLocks(List.of( - new RecordSecurityLock() - .withFieldName("clientId") - .withSecurityKeyType("crmClientAccess") - .withNullValueBehavior(NullValueBehavior.DENY) - )); + .withDefaultBackendNameForTables("rdbms"); + +new CrmQBitProducer() + .withQBitConfig(crmConfig) + .produce(qInstance) + .addSelfToInstance(qInstance); + +qInstance.setEnforcePermissionsInCoreActions(true); ``` -This injects a `clientId` security field onto all root CRM tables (Contact, Company, Deal, Pipeline) and propagates security locks through join chains to child tables. Users only see records matching their security key values. +4. Map the host's authenticated roles to the permissions below. Configure the host's core audit storage. Add tables, processes and widgets to the host UI as needed: `produceAppSection()` currently returns an empty CRM section; P1 does not provide an assembled app or home dashboard. -### Step 7 (optional): Companion QBits +## Configuration and access -The CRM integrates with other QBits for enhanced functionality: +- `defaultBackendNameForTables`: required backend name. +- `inferBackendNames`: defaults to true; sets snake_case SQL column names while Java/QQQ field names remain camelCase. SQL table names equal the QQQ table names. Set false only for an explicit host column mapping. +- `tableMetaDataCustomizer`: optional host table customizer. +- `securityFields` and `recordSecurityLocks`: retained in P1, applied to contact, company and deal. Host-managed schema columns must match these fields. This is not yet tenant isolation across every child table or workflow. -```java -CrmQBitConfig crmConfig = new CrmQBitConfig() - .withDefaultBackendNameForTables("rdbms") - .withQuickSearchQBitNamespace("quickSearch") // full-text search across contacts/companies/deals - .withWebhooksQBitNamespace("webhooks") // fire events on CRM changes (deal won, contact created, etc.) - .withWorkflowsQBitNamespace("workflows"); // user-defined automation rules -``` +| Scope | Permissions | +|---|---| +| Main and sub-tables | `crm.read`, `crm.write` | +| Settings tables except currency | `crm.manage.read`, `crm.manage.write` | +| Currency | `crm.admin.read`, `crm.admin.write` | +| Widgets and everyday processes | `crm.hasAccess` | +| Merge, bulk assignment, list and sequence management processes | `crm.manage.hasAccess` | +| GDPR anonymization | `crm.admin.hasAccess` | -Each companion QBit must be separately added as a Maven dependency and produced into your QInstance. The namespace strings must match the namespaces you used when producing those QBits. +Permissions are independent grants. Every CRM-produced table, process and widget has explicit `QPermissionRules` with `DenyBehavior.HIDDEN` and QBit provenance. `security.CrmPermissions.ALL` lists the grants for host administration and tests. The widget provenance adapter supplies core's `SourceQBitAware` interface because RC.6's widget class lacks it. -### Complete example +## Tables -```java -public void defineQInstance(QInstance qInstance) -{ - /////////////// - // backend // - /////////////// - qInstance.addBackend(new RDBMSBackendMetaData() - .withName("rdbms") - .withVendor("postgresql") - .withHostName("localhost") - .withDatabaseName("myapp") - .withUsername("myapp") - .withPassword("secret")); +All 33 table names and table-backed possible-value sources use `crm_` snake_case. The 23 enum possible-value sources retain their enum names. Relationship columns have indexes; the reference DDL does not impose foreign-key constraints or host-specific tenant columns. Unique constraints match the current QQQ metadata. - //////////////////// - // authentication // - //////////////////// - qInstance.setAuthentication(new Auth0AuthenticationMetaData() - .withType(QAuthenticationType.AUTH_0) - // ... auth config ... - ); +### Main tables (6) - ////////// - // CRM // - ////////// - CrmQBitConfig crmConfig = new CrmQBitConfig() - .withDefaultBackendNameForTables("rdbms"); +`crm_contact`, `crm_company`, `crm_deal`, `crm_activity`, `crm_form_submission`, `crm_email_list`. - new CrmQBitProducer() - .withQBitConfig(crmConfig) - .produce(qInstance) - .addSelfToInstance(qInstance); +### Settings tables (15) - ////////// - // App // - ////////// - qInstance.addApp(new QAppMetaData() - .withName("myApp") - .withSections(List.of( - CrmQBitProducer.produceAppSection() - ))); -} -``` +`crm_pipeline`, `crm_product`, `crm_email_template`, `crm_email_sequence`, `crm_lead_score_rule`, `crm_assignment_rule`, `crm_sales_goal`, `crm_currency`, `crm_lifecycle_stage`, `crm_lead_source`, `crm_industry`, `crm_activity_type`, `crm_activity_outcome`, `crm_contact_role`, `crm_win_loss_reason`. -## Data Model +### Sub-tables (12) -### Tables (39 total) +`crm_pipeline_stage`, `crm_consent_record`, `crm_email_list_member`, `crm_email_message`, `crm_sequence_step`, `crm_sequence_enrollment`, `crm_deal_contact`, `crm_deal_product`, `crm_deal_stage_history`, `crm_activity_participant`, `crm_assignment_rule_member`, `crm_external_mapping`. -#### Core (Phase 1a) +Contact, company, deal and activity declare core FIELD-level audit rules. The bespoke tag tables, attachment table, audit-log table and bulk tag processes have been removed. 0.2.0 is a fresh-install release with no upgrade path from 0.1.0. Collaboration replacements arrive in a later phase. -| Table | Description | -|-------|-------------| -| `crmContact` | People with lifecycle stages, lead scoring, consent tracking | -| `crmCompany` | Organizations with industry, type, parent-child hierarchy | -| `crmLifecycleStage` | Configurable contact lifecycle (Lead, MQL, SQL, Customer, etc.) | -| `crmLeadSource` | How contacts were acquired (Website, Referral, etc.) | -| `crmIndustry` | Industry classification for companies | -| `crmTag` | Free-form tags for categorizing records | -| `crmContactTag` / `crmCompanyTag` | Tag junction tables | -| `crmAttachment` | File attachments on any entity (polymorphic) | -| `crmConsentRecord` | GDPR consent tracking (append-only) | -| `crmFormSubmission` | Website form capture with UTM parameters | -| `crmEmailList` | Marketing mailing lists | -| `crmEmailListMember` | List subscribers (standalone or linked to contacts) | -| `crmCurrency` | Exchange rates for multi-currency support | -| `crmAuditLog` | Immutable field-level change tracking | +## Processes -#### Activities +The QBit produces 25 processes with these names and labels. QQQ may additionally generate standard table actions such as `.bulkInsert`; those retain core's naming conventions. CRM processes are available to host wiring and are not registered as scheduled jobs. -| Table | Description | -|-------|-------------| -| `crmActivity` | Unified table for calls, emails, meetings, notes, tasks | -| `crmActivityType` | Configurable activity types with icons | -| `crmActivityOutcome` | Call/meeting outcomes (Connected, No Answer, etc.) | -| `crmActivityParticipant` | Additional participants on activities | +| Process name | Label | +|---|---| +| `crm_auto_assign` | Auto Assign | +| `crm_bulk_assign_owner` | Bulk Assign Owner | +| `crm_calculate_lead_scores` | Calculate Lead Scores | +| `crm_clone_deal` | Clone Deal | +| `crm_convert_form_to_contact` | Convert Form to Contact | +| `crm_convert_lead` | Convert Lead | +| `crm_detect_duplicates` | Detect Duplicates | +| `crm_enroll_in_sequence` | Enroll in Sequence | +| `crm_fire_reminders` | Fire Reminders | +| `crm_gdpr_anonymize_contact` | GDPR Anonymize Contact | +| `crm_import_contacts` | Import Contacts | +| `crm_log_activity` | Log Activity | +| `crm_manage_contact_on_deal` | Manage Contact on Deal | +| `crm_merge_companies` | Merge Companies | +| `crm_merge_contacts` | Merge Contacts | +| `crm_move_deal_stage` | Move Deal Stage | +| `crm_process_overdue_tasks` | Process Overdue Tasks | +| `crm_process_sequence_steps` | Process Sequence Steps | +| `crm_reopen_deal` | Reopen Deal | +| `crm_send_email` | Send Email | +| `crm_subscribe_to_list` | Subscribe to List | +| `crm_track_email_event` | Track Email Event | +| `crm_transfer_ownership` | Transfer Ownership | +| `crm_unenroll_from_sequence` | Unenroll from Sequence | +| `crm_unsubscribe_from_list` | Unsubscribe from List | -#### Deals & Pipeline (Phase 1b) +## Current behavior and limits -| Table | Description | -|-------|-------------| -| `crmPipeline` | Pipeline definitions (multiple pipelines supported) | -| `crmPipelineStage` | Stages with probability, rot days, required-field gating | -| `crmDeal` | Deals with multi-currency, weighted amounts, probability override | -| `crmDealContact` | Contact-to-deal junction with roles and primary flag | -| `crmContactRole` | Roles contacts play on deals (Decision Maker, etc.) | -| `crmWinLossReason` | Win/loss reasons for closed deals | -| `crmDealTag` | Deal tag junction | -| `crmDealStageHistory` | Stage transition log for pipeline analytics | +The existing pipeline/stage logic, stage history, product totals, currency conversion, contact/company merge, activity logging, form auto-linking, list subscribe/unsubscribe, scoring and assignment processes remain. Fourteen custom dashboard widget producers remain available for host placement, together with generated child-record widgets. -#### Email (Phase 2) +Some process names describe unfinished behavior inherited from 0.1.0: -| Table | Description | -|-------|-------------| -| `crmEmailTemplate` | Reusable templates with merge field support | -| `crmEmailMessage` | Tracked emails with open/click/bounce/spam detection | +- Send Email and sequence email steps record CRM activity/message state; they do not deliver email. Template merging and live delivery tracking are not implemented here. +- Sequence execution, lead scoring and overdue-task work require host invocation. No schedules are shipped. Assignment is a process, not an automatic insert hook; reminders do not deliver notifications. +- Scoring's date-decay operators remain unimplemented. Import Contacts expects pre-parsed input and does not provide the planned streamed bulk-load workflow. +- GDPR anonymization scrubs the contact, unenrolls sequences and records withdrawn consent. It does not yet erase all linked PII or core audit details. The P1 schema retains existing PII fields; classification, complete erasure and redesigned tenancy are later work. -#### Products (Phase 2) +The later intake APIs, public subscription routes, collaboration integration, real email transport, durable jobs and full app navigation are not part of this phase. -| Table | Description | -|-------|-------------| -| `crmProduct` | Product catalog with SKU and pricing | -| `crmDealProduct` | Line items on deals with quantity, discount, calculated totals | +## Source layout -#### Sequences & Scoring (Phase 3) +`CrmQBitProducer` discovers entity, process and widget producers. `core/` holds contacts, companies, forms, lists and consent; `deals/`, `activities/`, `email/` and `scoring/` hold their respective metadata and behavior. `security/` defines permissions, `sync/` holds external mappings and currency utilities, and `widgets/` contains widget producers/renderers. SQL is shipped under `src/main/resources/db/liquibase/qbit-crm/`. -| Table | Description | -|-------|-------------| -| `crmEmailSequence` | Multi-step outreach sequences with send windows | -| `crmSequenceStep` | Individual steps (email, call, task, wait) | -| `crmSequenceEnrollment` | Contact enrollment tracking with failure handling | -| `crmLeadScoreRule` | Scoring rules with dot-notation field paths | -| `crmAssignmentRule` | Auto-assignment rules (round-robin, least-active, specific user) | -| `crmAssignmentRuleMember` | Users in assignment pools | -| `crmSalesGoal` | Revenue quotas per user per period | - -#### Sync (Phase 2) - -| Table | Description | -|-------|-------------| -| `crmExternalMapping` | Bidirectional sync mapping for external systems | - -### Enum PossibleValueSources (24) - -CrmEntityType, CrmCompanyType, CrmDealPriority, CrmActivityPriority, CrmDirection, CrmBounceType, CrmWinLossType, CrmParticipantRole, CrmSequenceStepType, CrmEnrollmentStatus, CrmEmailStatus, CrmScorableEntity, CrmScoreOperator, CrmAssignableEntity, CrmAssignStrategy, CrmConsentType, CrmConsentStatus, CrmLegalBasis, CrmGoalPeriod, CrmSyncStatus, CrmAuditAction, CrmFormType, CrmFormConversionStatus, CrmListMemberStatus - -## Processes (27) - -### Core Operations - -| Process | Description | -|---------|-------------| -| `logActivity` | Quick-log a call, meeting, note, or task from any record | -| `convertFormToContact` | Convert website form submission to CRM contact | -| `bulkConvertForms` | Batch convert multiple form submissions | -| `subscribeToList` / `unsubscribeFromList` | Mailing list management | -| `bulkAssignOwner` | Reassign record ownership in bulk | -| `bulkAddTag` / `bulkRemoveTag` | Tag management in bulk | -| `transferOwnership` | Transfer all records from one user to another | - -### Deal Operations - -| Process | Description | -|---------|-------------| -| `moveDealStage` | Move deal to new stage with required-field validation | -| `reopenDeal` | Reopen a closed deal to an active stage | -| `convertLead` | Convert contact to deal (atomic: lifecycle + deal + junction) | -| `manageContactOnDeal` | Add/remove contacts with role and primary flag enforcement | -| `cloneDeal` | Duplicate deal with contacts, products, and tags | - -### Email & Sequences - -| Process | Description | -|---------|-------------| -| `sendEmail` | Compose and send tracked email with template resolution | -| `trackEmailEvent` | Webhook callback for open/click/bounce/spam events | -| `enrollInSequence` | Enroll contacts in multi-step sequences | -| `processSequenceSteps` | Scheduled: execute pending sequence steps (5 min interval) | -| `unenrollFromSequence` | Remove contact from active sequence | - -### Scoring & Assignment - -| Process | Description | -|---------|-------------| -| `calculateLeadScores` | Scheduled daily: recalculate scores from rules | -| `autoAssign` | POST_INSERT hook: first-match rule-based assignment | - -### Data Management - -| Process | Description | -|---------|-------------| -| `mergeContacts` / `mergeCompanies` | Merge duplicates with unique-key conflict resolution | -| `importContacts` | CSV import with validation and duplicate detection | -| `detectDuplicates` | Find duplicate contacts by email or companies by domain | -| `gdprAnonymizeContact` | Right-to-erasure: anonymize PII, scrub audit log, delete attachments | - -### Scheduled Maintenance - -| Process | Description | -|---------|-------------| -| `processOverdueTasks` | Hourly: detect overdue task activities | -| `fireReminders` | Every 5 min: fire and clear activity reminders | - -## Widgets (14) - -| Widget | Type | Description | -|--------|------|-------------| -| `crmPipelineSummary` | Table | Deal count and amount per stage | -| `crmActivityFeed` | Table | Most recent activities across all entities | -| `crmDealForecast` | Table | Weighted pipeline by expected close month | -| `crmRottingDeals` | Table | Deals exceeding stage rot threshold | -| `crmContactTimeline` | Stepper | Per-contact activity timeline | -| `crmActivityCount` | Statistics | Activity counts by type (today/week/month) | -| `crmRecentDeals` | Table | Recently won/lost deals | -| `crmSalesLeaderboard` | Table | Users ranked by closed-won revenue | -| `crmQuotaAttainment` | Statistics | Won revenue vs. sales goal target | -| `crmPipelineConversion` | Table | Stage-to-stage conversion rates | -| `crmStageDuration` | Table | Average days per pipeline stage | -| `crmWinRate` | Table | Win rate trend over time | -| `crmAvgDealSize` | Table | Average won deal size | -| `crmSalesCycleLength` | Table | Average days from creation to close | - -## Companion QBit Integration - -### qbit-quick-search (ElasticSearch) - -Index `crmContact`, `crmCompany`, and `crmDeal` for full-text global search. - -### qbit-webhooks - -Supported event types: - -| Event | Fires When | -|-------|------------| -| `crm.contact.created` / `crm.contact.updated` | Contact inserted or updated | -| `crm.company.created` / `crm.company.updated` | Company inserted or updated | -| `crm.deal.created` / `crm.deal.stageChanged` | Deal created or stage changed | -| `crm.deal.won` / `crm.deal.lost` | Deal moved to terminal stage | -| `crm.activity.created` | Activity logged | -| `crm.consent.changed` | Consent granted or withdrawn | -| `crm.form.submitted` / `crm.form.converted` | Form submitted or converted to contact | - -### qbit-workflows - -User-defined automation beyond built-in scoring/assignment. The CRM does not re-implement a workflow engine. - -## Phased Delivery - -| Phase | Tables | Processes | Widgets | Focus | -|-------|--------|-----------|---------|-------| -| 1a | 18 | 7 | 6 | Core + Website Integration | -| 1b | 8 | 4 | 3 | Deals + Pipeline | -| 2 | 5 | 7 | 1 | Email, Products, Scheduling | -| 3 | 7 | 5 | 2 | Sequences, Scoring, Automation | -| 4 | 1 | 7 | 5 | Data Management, Analytics, GDPR | -| **Total** | **39** | **30** | **14** | | - -## Testing - -```bash -mvn test # Run all 271 tests -mvn test -Dtest=BaseTest # Verify QBit produces metadata -``` - -### Coverage - -- **91.5% instruction coverage** (Jacoco) -- **73 test classes** covering all entities, processes, widgets, and customizers -- All tests run in-memory via MemoryRecordStore (no database required) - -```bash -mvn org.jacoco:jacoco-maven-plugin:0.8.11:prepare-agent test \ - org.jacoco:jacoco-maven-plugin:0.8.11:report -# Report at: target/site/jacoco/index.html -``` - -## Documentation - -- **[QQQ Wiki](https://github.com/Kingsrook/qqq/wiki)** - Framework documentation -- **[QBit Development Guide](https://github.com/Kingsrook/qqq/wiki/QBit-Development)** - How QBits work -- **Design Spec** - Full data model and architecture in `QRun-IO/specs/2026-03-28-qbit-crm-design-v2.md` - -## Contributing - -QBit CRM is open source and welcomes contributions. - -- **[Report Issues](https://github.com/QRun-IO/qqq/issues)** - Bug reports and feature requests -- **[QQQ Contribution Guide](https://github.com/Kingsrook/qqq/wiki/Contribution-Guidelines)** - How to contribute - -## About Kingsrook - -QBit CRM is built by **[Kingsrook](https://qrun.io)** - making engineers more productive through intelligent automation and developer tools. - -- **Website**: [https://qrun.io](https://qrun.io) -- **Contact**: [contact@kingsrook.com](mailto:contact@kingsrook.com) -- **GitHub**: [https://github.com/QRun-IO](https://github.com/QRun-IO) - -## License - -This project is licensed under the **Apache License, Version 2.0** - see the [LICENSE](LICENSE) file for details. +Licensed under [Apache License 2.0](LICENSE). diff --git a/checkstyle/config.xml b/checkstyle/config.xml index 78c2f49..385d653 100644 --- a/checkstyle/config.xml +++ b/checkstyle/config.xml @@ -6,18 +6,17 @@ ~ contact@kingsrook.com ~ https://github.com/Kingsrook/ ~ - ~ This program is free software: you can redistribute it and/or modify - ~ it under the terms of the GNU Affero General Public License as - ~ published by the Free Software Foundation, either version 3 of the - ~ License, or (at your option) any later version. + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at ~ - ~ This program is distributed in the hope that it will be useful, - ~ but WITHOUT ANY WARRANTY; without even the implied warranty of - ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - ~ GNU Affero General Public License for more details. + ~ https://www.apache.org/licenses/LICENSE-2.0 ~ - ~ You should have received a copy of the GNU Affero General Public License - ~ along with this program. If not, see . + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. --> &2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +scriptDir="$(dirname "$0")" +scriptName="$(basename "$0")" + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +actualDistributionDir="" + +# First try the expected directory name (for regular distributions) +if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then + if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then + actualDistributionDir="$distributionUrlNameMain" + fi +fi + +# If not found, search for any directory with the Maven executable (for snapshots) +if [ -z "$actualDistributionDir" ]; then + # enable globbing to iterate over items + set +f + for dir in "$TMP_DOWNLOAD_DIR"/*; do + if [ -d "$dir" ]; then + if [ -f "$dir/bin/$MVN_CMD" ]; then + actualDistributionDir="$(basename "$dir")" + break + fi + fi + done + set -f +fi + +if [ -z "$actualDistributionDir" ]; then + verbose "Contents of $TMP_DOWNLOAD_DIR:" + verbose "$(ls -la "$TMP_DOWNLOAD_DIR")" + die "Could not find Maven distribution directory in extracted archive" +fi + +verbose "Found extracted Maven distribution directory: $actualDistributionDir" +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..92450f9 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,189 @@ +<# : batch portion +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.4 +@REM +@REM Optional ENV vars +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output +@REM ---------------------------------------------------------------------------- + +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) +) +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' + +$MAVEN_M2_PATH = "$HOME/.m2" +if ($env:MAVEN_USER_HOME) { + $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME" +} + +if (-not (Test-Path -Path $MAVEN_M2_PATH)) { + New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null +} + +$MAVEN_WRAPPER_DISTS = $null +if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) { + $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists" +} else { + $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists" +} + +$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain" +$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +$actualDistributionDir = "" + +# First try the expected directory name (for regular distributions) +$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain" +$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD" +if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) { + $actualDistributionDir = $distributionUrlNameMain +} + +# If not found, search for any directory with the Maven executable (for snapshots) +if (!$actualDistributionDir) { + Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object { + $testPath = Join-Path $_.FullName "bin/$MVN_CMD" + if (Test-Path -Path $testPath -PathType Leaf) { + $actualDistributionDir = $_.Name + } + } +} + +if (!$actualDistributionDir) { + Write-Error "Could not find Maven distribution directory in extracted archive" +} + +Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir" +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/pom.xml b/pom.xml index bbed79e..5fa2879 100644 --- a/pom.xml +++ b/pom.xml @@ -22,13 +22,18 @@ - 0.1.0 + 0.2.0-SNAPSHOT + 21 + 21 + 0.8.15 + true + true com.kingsrook qbit-build-parent - 1.4.0 + 2.1.2 com.kingsrook.qbits @@ -82,7 +87,7 @@ com.h2database h2 - 2.2.220 + 2.3.232 test @@ -95,9 +100,101 @@ org.assertj assertj-core - 3.27.3 + 3.27.7 test + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.6.0 + + checkstyle/config.xml + true + warning + + + + checkstyle + validate + check + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + prepare-agent + + prepare-agent + + + + report + verify + + report + + + + check + + check + + + + + BUNDLE + + + INSTRUCTION + COVEREDRATIO + 0.70 + + + CLASS + COVEREDRATIO + 0.90 + + + + + + + + + + + + + + + + + qqq-snapshot + + true + + + 4.1.0-RC.6 + + + + + com.kingsrook.qqq + qqq-bom-pom + ${qqq.snapshot.version} + pom + import + + + + + diff --git a/src/main/java/com/kingsrook/qbits/crm/CrmQBitConfig.java b/src/main/java/com/kingsrook/qbits/crm/CrmQBitConfig.java index 9475b2d..053065c 100644 --- a/src/main/java/com/kingsrook/qbits/crm/CrmQBitConfig.java +++ b/src/main/java/com/kingsrook/qbits/crm/CrmQBitConfig.java @@ -1,37 +1,54 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Configuration for the CRM QBit. *******************************************************************************/ + package com.kingsrook.qbits.crm; -import java.util.ArrayList; import java.util.List; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.producers.MetaDataCustomizerInterface; import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitConfig; import com.kingsrook.qqq.backend.core.model.metadata.security.RecordSecurityLock; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.producers.MetaDataCustomizerInterface; import com.kingsrook.qqq.backend.core.utils.StringUtils; /******************************************************************************* ** QBitConfig for the CRM QBit. Holds backend name, security configuration, - ** table metadata customizer, and companion QBit namespace references. + ** table metadata customizer and backend column naming. *******************************************************************************/ public class CrmQBitConfig implements QBitConfig { public static final CrmQBitConfig DEFAULT_CONFIG = new CrmQBitConfig(); private String defaultBackendNameForTables; - private String tableNamePrefix; + private Boolean inferBackendNames = true; private MetaDataCustomizerInterface tableMetaDataCustomizer; private List securityFields; private List recordSecurityLocks; - private String quickSearchQBitNamespace; - private String webhooksQBitNamespace; - private String workflowsQBitNamespace; - /******************************************************************************* @@ -110,27 +127,6 @@ public class CrmQBitConfig implements QBitConfig - /******************************************************************************* - ** Getter for tableNamePrefix - *******************************************************************************/ - public String getTableNamePrefix() - { - return (this.tableNamePrefix); - } - - - - /******************************************************************************* - ** Fluent setter for tableNamePrefix - *******************************************************************************/ - public CrmQBitConfig withTableNamePrefix(String tableNamePrefix) - { - this.tableNamePrefix = tableNamePrefix; - return (this); - } - - - /******************************************************************************* ** Getter for securityFields *******************************************************************************/ @@ -174,63 +170,21 @@ public class CrmQBitConfig implements QBitConfig /******************************************************************************* - ** Getter for quickSearchQBitNamespace + ** Whether to infer snake_case database column names. *******************************************************************************/ - public String getQuickSearchQBitNamespace() + public Boolean getInferBackendNames() { - return (this.quickSearchQBitNamespace); + return (this.inferBackendNames); } /******************************************************************************* - ** Fluent setter for quickSearchQBitNamespace + ** Configure automatic database column naming. *******************************************************************************/ - public CrmQBitConfig withQuickSearchQBitNamespace(String quickSearchQBitNamespace) + public CrmQBitConfig withInferBackendNames(Boolean inferBackendNames) { - this.quickSearchQBitNamespace = quickSearchQBitNamespace; - return (this); - } - - - - /******************************************************************************* - ** Getter for webhooksQBitNamespace - *******************************************************************************/ - public String getWebhooksQBitNamespace() - { - return (this.webhooksQBitNamespace); - } - - - - /******************************************************************************* - ** Fluent setter for webhooksQBitNamespace - *******************************************************************************/ - public CrmQBitConfig withWebhooksQBitNamespace(String webhooksQBitNamespace) - { - this.webhooksQBitNamespace = webhooksQBitNamespace; - return (this); - } - - - - /******************************************************************************* - ** Getter for workflowsQBitNamespace - *******************************************************************************/ - public String getWorkflowsQBitNamespace() - { - return (this.workflowsQBitNamespace); - } - - - - /******************************************************************************* - ** Fluent setter for workflowsQBitNamespace - *******************************************************************************/ - public CrmQBitConfig withWorkflowsQBitNamespace(String workflowsQBitNamespace) - { - this.workflowsQBitNamespace = workflowsQBitNamespace; + this.inferBackendNames = inferBackendNames; return (this); } diff --git a/src/main/java/com/kingsrook/qbits/crm/CrmQBitProducer.java b/src/main/java/com/kingsrook/qbits/crm/CrmQBitProducer.java index df915c9..1ccdec2 100644 --- a/src/main/java/com/kingsrook/qbits/crm/CrmQBitProducer.java +++ b/src/main/java/com/kingsrook/qbits/crm/CrmQBitProducer.java @@ -1,31 +1,61 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QBitMetaDataProducer for the CRM QBit. *******************************************************************************/ + package com.kingsrook.qbits.crm; -import java.util.List; +import java.util.Locale; import com.kingsrook.qbits.crm.activities.customizers.ActivityLastDateCustomizer; import com.kingsrook.qbits.crm.activities.model.Activity; import com.kingsrook.qbits.crm.core.customizers.FormSubmissionAutoLinkCustomizer; -import com.kingsrook.qbits.crm.core.model.FormSubmission; -import com.kingsrook.qbits.crm.audit.customizers.CrmAuditLogCustomizer; import com.kingsrook.qbits.crm.core.model.Company; import com.kingsrook.qbits.crm.core.model.Contact; +import com.kingsrook.qbits.crm.core.model.FormSubmission; import com.kingsrook.qbits.crm.deals.customizers.DealInitializationCustomizer; import com.kingsrook.qbits.crm.deals.customizers.DealProductRecalculationCustomizer; import com.kingsrook.qbits.crm.deals.customizers.DealStageChangeCustomizer; import com.kingsrook.qbits.crm.deals.model.Deal; import com.kingsrook.qbits.crm.deals.model.DealProduct; +import com.kingsrook.qbits.crm.security.CrmPermissions; +import com.kingsrook.qbits.crm.widgets.CrmWidgetMetaData; import com.kingsrook.qqq.backend.core.actions.customizers.MultiCustomizer; import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers; import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.instances.QInstanceEnricher; import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerMultiOutput; +import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerOutput; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; +import com.kingsrook.qqq.backend.core.model.metadata.audits.AuditLevel; +import com.kingsrook.qqq.backend.core.model.metadata.audits.QAuditRules; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReferenceWithProperties; +import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData; import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppSection; import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon; +import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitMetaData; import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitMetaDataProducer; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; @@ -39,7 +69,7 @@ public class CrmQBitProducer implements QBitMetaDataProducer { public static final String GROUP_ID = "com.kingsrook.qbits"; public static final String ARTIFACT_ID = "crm"; - public static final String VERSION = "0.1.0"; + public static final String VERSION = "0.2.0-SNAPSHOT"; private CrmQBitConfig qBitConfig; @@ -67,12 +97,48 @@ public class CrmQBitProducer implements QBitMetaDataProducer @Override public void postProduceActions(MetaDataProducerMultiOutput metaDataProducerMultiOutput, QInstance qInstance) throws QException { + for(QJoinMetaData join : metaDataProducerMultiOutput.getEach(QJoinMetaData.class)) + { + join.setName(snakeCase(join.getName())); + } + for(QWidgetMetaData widget : metaDataProducerMultiOutput.getEach(QWidgetMetaData.class)) + { + widget.setName(snakeCase(widget.getName())); + widget.setPermissionRules(CrmPermissions.hasAccessRules(CrmPermissions.BASE)); + if(widget.getDefaultValues() != null && widget.getDefaultValues().get("joinName") instanceof String joinName) + { + widget.withDefaultValue("joinName", snakeCase(joinName)); + } + } + + for(QProcessMetaData process : metaDataProducerMultiOutput.getEach(QProcessMetaData.class)) + { + process.setPermissionRules(CrmPermissions.processRules(process.getName())); + process.setSourceQBitName(getQBitMetaData().getName()); + } + ///////////////////////////////////////////////////////////////////////// // iterate tables produced by this QBit and register customizers // ///////////////////////////////////////////////////////////////////////// for(QTableMetaData table : metaDataProducerMultiOutput.getEach(QTableMetaData.class)) { String tableName = table.getName(); + table.setPermissionRules(CrmPermissions.tableRules(tableName)); + table.setSourceQBitName(getQBitMetaData().getName()); + if(table.getSections() != null) + { + table.getSections().forEach(section -> + { + if(section.getWidgetName() != null) + { + section.setWidgetName(snakeCase(section.getWidgetName())); + } + }); + } + if(Boolean.TRUE.equals(qBitConfig.getInferBackendNames())) + { + QInstanceEnricher.setInferredFieldBackendNames(table); + } /////////////////////////////////////////////////////////////// // wire audit log on tracked entities // @@ -80,10 +146,7 @@ public class CrmQBitProducer implements QBitMetaDataProducer if(tableName.equals(Contact.TABLE_NAME) || tableName.equals(Company.TABLE_NAME) || tableName.equals(Deal.TABLE_NAME) || tableName.equals(Activity.TABLE_NAME)) { - QCodeReference auditRef = new QCodeReference(CrmAuditLogCustomizer.class); - addOrComposeCustomizer(table, TableCustomizers.POST_INSERT_RECORD, auditRef); - addOrComposeCustomizer(table, TableCustomizers.POST_UPDATE_RECORD, auditRef); - addOrComposeCustomizer(table, TableCustomizers.POST_DELETE_RECORD, auditRef); + table.withAuditRules(new QAuditRules().withAuditLevel(AuditLevel.FIELD)); } /////////////////////////////////////////////////////////////// @@ -209,4 +272,28 @@ public class CrmQBitProducer implements QBitMetaDataProducer return (this); } + /******************************************************************************* + ** Normalize generated metadata names as well as explicit CRM names. + *******************************************************************************/ + private static String snakeCase(String name) + { + return (name.replaceAll("([a-z0-9])([A-Z])", "$1_$2").toLowerCase(Locale.ROOT)); + } + + /******************************************************************************* + ** Add widget provenance after the standard package-discovered production. + *******************************************************************************/ + @Override + public MetaDataProducerMultiOutput produce(QInstance qInstance) throws QException + { + MetaDataProducerMultiOutput produced = QBitMetaDataProducer.super.produce(qInstance); + MetaDataProducerMultiOutput output = new MetaDataProducerMultiOutput(); + for(MetaDataProducerOutput item : produced.getEach(MetaDataProducerOutput.class)) + { + output.add(item instanceof QWidgetMetaData widget + ? new CrmWidgetMetaData(widget).withSourceQBitName(getQBitMetaData().getName()) : item); + } + return (output); + } + } diff --git a/src/main/java/com/kingsrook/qbits/crm/CrmSessionUtils.java b/src/main/java/com/kingsrook/qbits/crm/CrmSessionUtils.java index ffd574a..dc3a016 100644 --- a/src/main/java/com/kingsrook/qbits/crm/CrmSessionUtils.java +++ b/src/main/java/com/kingsrook/qbits/crm/CrmSessionUtils.java @@ -1,7 +1,29 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Utility class for null-safe session user ID resolution. Used by processes ** and customizers that need the current user ID for audit logging. *******************************************************************************/ + package com.kingsrook.qbits.crm; diff --git a/src/main/java/com/kingsrook/qbits/crm/activities/customizers/ActivityLastDateCustomizer.java b/src/main/java/com/kingsrook/qbits/crm/activities/customizers/ActivityLastDateCustomizer.java index a8bac86..d66d903 100644 --- a/src/main/java/com/kingsrook/qbits/crm/activities/customizers/ActivityLastDateCustomizer.java +++ b/src/main/java/com/kingsrook/qbits/crm/activities/customizers/ActivityLastDateCustomizer.java @@ -1,8 +1,30 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** POST_INSERT table customizer that propagates lastActivityDate and ** lastContactedDate to linked Contact, Company, and Deal records whenever ** a new Activity is created. *******************************************************************************/ + package com.kingsrook.qbits.crm.activities.customizers; diff --git a/src/main/java/com/kingsrook/qbits/crm/activities/model/Activity.java b/src/main/java/com/kingsrook/qbits/crm/activities/model/Activity.java index 8593262..114c6e9 100644 --- a/src/main/java/com/kingsrook/qbits/crm/activities/model/Activity.java +++ b/src/main/java/com/kingsrook/qbits/crm/activities/model/Activity.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for the crm_activity table. *******************************************************************************/ + package com.kingsrook.qbits.crm.activities.model; @@ -57,7 +79,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.Tier; ) public class Activity extends QRecordEntity { - public static final String TABLE_NAME = "crmActivity"; + public static final String TABLE_NAME = "crm_activity"; diff --git a/src/main/java/com/kingsrook/qbits/crm/activities/model/ActivityOutcome.java b/src/main/java/com/kingsrook/qbits/crm/activities/model/ActivityOutcome.java index 3ac6255..dd948c2 100644 --- a/src/main/java/com/kingsrook/qbits/crm/activities/model/ActivityOutcome.java +++ b/src/main/java/com/kingsrook/qbits/crm/activities/model/ActivityOutcome.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for the crm_activity_outcome table. *******************************************************************************/ + package com.kingsrook.qbits.crm.activities.model; @@ -30,7 +52,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; ) public class ActivityOutcome extends QRecordEntity { - public static final String TABLE_NAME = "crmActivityOutcome"; + public static final String TABLE_NAME = "crm_activity_outcome"; diff --git a/src/main/java/com/kingsrook/qbits/crm/activities/model/ActivityParticipant.java b/src/main/java/com/kingsrook/qbits/crm/activities/model/ActivityParticipant.java index 822630a..18a026e 100644 --- a/src/main/java/com/kingsrook/qbits/crm/activities/model/ActivityParticipant.java +++ b/src/main/java/com/kingsrook/qbits/crm/activities/model/ActivityParticipant.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for the crm_activity_participant table. *******************************************************************************/ + package com.kingsrook.qbits.crm.activities.model; @@ -29,7 +51,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.SectionFactory; ) public class ActivityParticipant extends QRecordEntity { - public static final String TABLE_NAME = "crmActivityParticipant"; + public static final String TABLE_NAME = "crm_activity_participant"; diff --git a/src/main/java/com/kingsrook/qbits/crm/activities/model/ActivityType.java b/src/main/java/com/kingsrook/qbits/crm/activities/model/ActivityType.java index aef48f3..6494195 100644 --- a/src/main/java/com/kingsrook/qbits/crm/activities/model/ActivityType.java +++ b/src/main/java/com/kingsrook/qbits/crm/activities/model/ActivityType.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for the crm_activity_type table. *******************************************************************************/ + package com.kingsrook.qbits.crm.activities.model; @@ -34,7 +56,7 @@ import com.kingsrook.qqq.backend.core.model.statusmessages.BadInputStatusMessage ) public class ActivityType extends QRecordEntity { - public static final String TABLE_NAME = "crmActivityType"; + public static final String TABLE_NAME = "crm_activity_type"; diff --git a/src/main/java/com/kingsrook/qbits/crm/activities/processes/FireRemindersProcess.java b/src/main/java/com/kingsrook/qbits/crm/activities/processes/FireRemindersProcess.java index a03b9af..379f0ed 100644 --- a/src/main/java/com/kingsrook/qbits/crm/activities/processes/FireRemindersProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/activities/processes/FireRemindersProcess.java @@ -1,7 +1,29 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Scheduled process that fires reminders for activities with isReminderSet ** = true and reminderDate <= now. Clears the reminder flag after processing. *******************************************************************************/ + package com.kingsrook.qbits.crm.activities.processes; @@ -37,7 +59,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; *******************************************************************************/ public class FireRemindersProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "fireReminders"; + public static final String NAME = "crm_fire_reminders"; diff --git a/src/main/java/com/kingsrook/qbits/crm/activities/processes/LogActivityProcess.java b/src/main/java/com/kingsrook/qbits/crm/activities/processes/LogActivityProcess.java index 29db789..8183992 100644 --- a/src/main/java/com/kingsrook/qbits/crm/activities/processes/LogActivityProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/activities/processes/LogActivityProcess.java @@ -1,7 +1,29 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Process to log a CRM activity. Creates a single crm_activity record with ** the provided fields and sets ownerUserId from the current session user. *******************************************************************************/ + package com.kingsrook.qbits.crm.activities.processes; @@ -16,11 +38,11 @@ import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; +import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; @@ -37,7 +59,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; *******************************************************************************/ public class LogActivityProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "logActivity"; + public static final String NAME = "crm_log_activity"; diff --git a/src/main/java/com/kingsrook/qbits/crm/activities/processes/ProcessOverdueTasksProcess.java b/src/main/java/com/kingsrook/qbits/crm/activities/processes/ProcessOverdueTasksProcess.java index 2055958..6dfc072 100644 --- a/src/main/java/com/kingsrook/qbits/crm/activities/processes/ProcessOverdueTasksProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/activities/processes/ProcessOverdueTasksProcess.java @@ -1,8 +1,30 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Scheduled process that finds overdue tasks and marks them with a system ** note. In production this would fire notifications; for now it logs a ** message on each overdue activity. *******************************************************************************/ + package com.kingsrook.qbits.crm.activities.processes; @@ -38,7 +60,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; *******************************************************************************/ public class ProcessOverdueTasksProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "processOverdueTasks"; + public static final String NAME = "crm_process_overdue_tasks"; diff --git a/src/main/java/com/kingsrook/qbits/crm/audit/customizers/CrmAuditLogCustomizer.java b/src/main/java/com/kingsrook/qbits/crm/audit/customizers/CrmAuditLogCustomizer.java deleted file mode 100644 index 4c2f376..0000000 --- a/src/main/java/com/kingsrook/qbits/crm/audit/customizers/CrmAuditLogCustomizer.java +++ /dev/null @@ -1,290 +0,0 @@ -/******************************************************************************* - ** POST_INSERT, POST_UPDATE, and POST_DELETE table customizer that creates - ** immutable audit log entries for tracked CRM entities. - ** - ** Registered globally on tracked tables (contact, company, deal, activity) - ** via MultiCustomizer in CrmQBitProducer.postProduceActions. - *******************************************************************************/ -package com.kingsrook.qbits.crm.audit.customizers; - - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import com.kingsrook.qbits.crm.audit.model.AuditLog; -import com.kingsrook.qbits.crm.core.model.enums.CrmAuditAction; -import com.kingsrook.qbits.crm.core.model.enums.CrmEntityType; -import com.kingsrook.qbits.crm.CrmSessionUtils; -import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizerInterface; -import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; -import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.logging.QLogger; -import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput; -import com.kingsrook.qqq.backend.core.model.data.QRecord; -import com.kingsrook.qqq.backend.core.utils.StringUtils; -import com.kingsrook.qqq.backend.core.utils.ValueUtils; - - -/******************************************************************************* - ** Audit log customizer that creates crm_audit_log entries for every insert, - ** update, and delete on tracked entities. For updates, field-level change - ** tracking captures old and new values, with special detection for owner - ** and pipeline stage changes. - *******************************************************************************/ -public class CrmAuditLogCustomizer implements TableCustomizerInterface -{ - private static final QLogger LOG = QLogger.getLogger(CrmAuditLogCustomizer.class); - - /////////////////////////////////////////////////////////////////////////// - // map of table names to CrmEntityType IDs for tracked entities // - /////////////////////////////////////////////////////////////////////////// - private static final Map TABLE_TO_ENTITY_TYPE = new HashMap<>(); - - static - { - TABLE_TO_ENTITY_TYPE.put("crmContact", CrmEntityType.CONTACT.getPossibleValueId()); - TABLE_TO_ENTITY_TYPE.put("crmCompany", CrmEntityType.COMPANY.getPossibleValueId()); - TABLE_TO_ENTITY_TYPE.put("crmDeal", CrmEntityType.DEAL.getPossibleValueId()); - TABLE_TO_ENTITY_TYPE.put("crmActivity", CrmEntityType.ACTIVITY.getPossibleValueId()); - } - - - - /******************************************************************************* - ** Post-insert: log a CREATED action for each inserted record. - *******************************************************************************/ - @Override - public List postInsert(InsertInput insertInput, List records) throws QException - { - String tableName = insertInput.getTableName(); - String userId = getCurrentUserId(); - - List auditRecords = new ArrayList<>(); - for(QRecord record : records) - { - if(record.getErrors() != null && !record.getErrors().isEmpty()) - { - continue; - } - - Integer entityId = ValueUtils.getValueAsInteger(record.getValue("id")); - if(entityId == null) - { - continue; - } - - auditRecords.add(buildAuditRecord(tableName, entityId, CrmAuditAction.CREATED, userId, - null, null, null, "Record created")); - } - - insertAuditRecords(auditRecords); - return (records); - } - - - - /******************************************************************************* - ** Post-update: log an UPDATED action per changed field, with special - ** detection for OWNER_CHANGED and STAGE_CHANGED actions. - *******************************************************************************/ - @Override - public List postUpdate(UpdateInput updateInput, List records, Optional> oldRecordList) throws QException - { - String tableName = updateInput.getTableName(); - String userId = getCurrentUserId(); - - Optional> oldRecordMap = oldRecordListToMap( - updateInput.getTable().getPrimaryKeyField(), oldRecordList); - - if(oldRecordMap.isEmpty()) - { - /////////////////////////////////////////////////////////////////////////// - // without old records, we cannot determine what changed -- skip logging // - /////////////////////////////////////////////////////////////////////////// - return (records); - } - - List auditRecords = new ArrayList<>(); - for(QRecord record : records) - { - if(record.getErrors() != null && !record.getErrors().isEmpty()) - { - continue; - } - - Serializable primaryKey = record.getValue(updateInput.getTable().getPrimaryKeyField()); - Integer entityId = ValueUtils.getValueAsInteger(primaryKey); - QRecord oldRecord = oldRecordMap.get().get(primaryKey); - - if(entityId == null || oldRecord == null) - { - continue; - } - - for(String fieldName : record.getValues().keySet()) - { - Serializable oldVal = oldRecord.getValue(fieldName); - Serializable newVal = record.getValue(fieldName); - - if(!Objects.equals(oldVal, newVal)) - { - String oldStr = oldVal == null ? null : String.valueOf(oldVal); - String newStr = newVal == null ? null : String.valueOf(newVal); - - ///////////////////////////////////////////////////////////////// - // determine the specific action for special tracked fields // - ///////////////////////////////////////////////////////////////// - CrmAuditAction auditAction = CrmAuditAction.UPDATED; - if("ownerUserId".equals(fieldName)) - { - auditAction = CrmAuditAction.OWNER_CHANGED; - } - else if("pipelineStageId".equals(fieldName)) - { - auditAction = CrmAuditAction.STAGE_CHANGED; - } - - auditRecords.add(buildAuditRecord(tableName, entityId, auditAction, userId, - fieldName, oldStr, newStr, null)); - } - } - } - - insertAuditRecords(auditRecords); - return (records); - } - - - - /******************************************************************************* - ** Post-delete: log a DELETED action for each deleted record. - *******************************************************************************/ - @Override - public List postDelete(DeleteInput deleteInput, List records) throws QException - { - String tableName = deleteInput.getTableName(); - String userId = getCurrentUserId(); - - List auditRecords = new ArrayList<>(); - for(QRecord record : records) - { - if(record.getErrors() != null && !record.getErrors().isEmpty()) - { - continue; - } - - Integer entityId = ValueUtils.getValueAsInteger(record.getValue("id")); - if(entityId == null) - { - continue; - } - - auditRecords.add(buildAuditRecord(tableName, entityId, CrmAuditAction.DELETED, userId, - null, null, null, "Record deleted")); - } - - insertAuditRecords(auditRecords); - return (records); - } - - - - /******************************************************************************* - ** Build a single audit log QRecord. - *******************************************************************************/ - private QRecord buildAuditRecord(String tableName, Integer entityId, CrmAuditAction action, - String userId, String fieldName, String oldValue, - String newValue, String message) - { - QRecord auditRecord = new QRecord(); - auditRecord.setValue("entityType", resolveEntityType(tableName)); - auditRecord.setValue("entityId", entityId); - auditRecord.setValue("action", action.getPossibleValueId()); - auditRecord.setValue("userId", userId); - - if(StringUtils.hasContent(fieldName)) - { - auditRecord.setValue("fieldName", fieldName); - } - - if(oldValue != null) - { - auditRecord.setValue("oldValue", oldValue); - } - - if(newValue != null) - { - auditRecord.setValue("newValue", newValue); - } - - if(StringUtils.hasContent(message)) - { - auditRecord.setValue("message", message); - } - - return (auditRecord); - } - - - - /******************************************************************************* - ** Resolve a table name to its CrmEntityType integer ID. - ** Returns the mapped ID if known, or falls back to the table name string - ** for unrecognized tables (allowing forward-compatibility). - *******************************************************************************/ - private Object resolveEntityType(String tableName) - { - Integer entityTypeId = TABLE_TO_ENTITY_TYPE.get(tableName); - if(entityTypeId != null) - { - return (entityTypeId); - } - - /////////////////////////////////////////////////////////////////////////// - // fallback: use the table name directly for unrecognized entity types // - /////////////////////////////////////////////////////////////////////////// - return (tableName); - } - - - - /******************************************************************************* - ** Insert a batch of audit log records using InsertAction. - *******************************************************************************/ - private void insertAuditRecords(List auditRecords) throws QException - { - if(auditRecords.isEmpty()) - { - return; - } - - try - { - InsertInput insertInput = new InsertInput(); - insertInput.setTableName(AuditLog.TABLE_NAME); - insertInput.setRecords(auditRecords); - new InsertAction().execute(insertInput); - } - catch(Exception e) - { - LOG.warn("Error inserting audit log records", e); - } - } - - - - /******************************************************************************* - ** Get the current user ID from the QContext session. - *******************************************************************************/ - private String getCurrentUserId() - { - return (CrmSessionUtils.getCurrentUserId()); - } - -} diff --git a/src/main/java/com/kingsrook/qbits/crm/audit/model/AuditLog.java b/src/main/java/com/kingsrook/qbits/crm/audit/model/AuditLog.java deleted file mode 100644 index 9c848d6..0000000 --- a/src/main/java/com/kingsrook/qbits/crm/audit/model/AuditLog.java +++ /dev/null @@ -1,481 +0,0 @@ -/******************************************************************************* - ** QRecord Entity for the immutable CRM audit log table. - *******************************************************************************/ -package com.kingsrook.qbits.crm.audit.model; - - -import java.time.Instant; -import java.util.List; -import com.kingsrook.qbits.crm.core.model.enums.CrmAuditAction; -import com.kingsrook.qbits.crm.core.model.enums.CrmEntityType; -import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPreDeleteCustomizer; -import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPreUpdateCustomizer; -import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers; -import com.kingsrook.qqq.backend.core.context.QContext; -import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; -import com.kingsrook.qqq.backend.core.model.data.QField; -import com.kingsrook.qqq.backend.core.model.data.QRecord; -import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; -import com.kingsrook.qqq.backend.core.model.metadata.QInstance; -import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; -import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon; -import com.kingsrook.qqq.backend.core.model.metadata.producers.MetaDataCustomizerInterface; -import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.QMetaDataProducingEntity; -import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection; -import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.tables.SectionFactory; -import com.kingsrook.qqq.backend.core.model.metadata.tables.Tier; - - -/******************************************************************************* - ** Immutable append-only audit ledger for tracked CRM entities. - ** Records field-level changes, stage transitions, owner changes, and lifecycle - ** events with full before/after values and user attribution. - *******************************************************************************/ -@QMetaDataProducingEntity( - producePossibleValueSource = false, - produceTableMetaData = true, - tableMetaDataCustomizer = AuditLog.TableMetaDataCustomizer.class -) -public class AuditLog extends QRecordEntity -{ - public static final String TABLE_NAME = "crmAuditLog"; - - - @QField(isEditable = false, isPrimaryKey = true) - private Integer id; - - @QField(isRequired = true, possibleValueSourceName = CrmEntityType.NAME) - private Integer entityType; - - @QField(isRequired = true) - private Integer entityId; - - @QField(isRequired = true, possibleValueSourceName = CrmAuditAction.NAME) - private Integer action; - - @QField(isRequired = true) - private String userId; - - @QField(maxLength = 100) - private String fieldName; - - @QField() - private String oldValue; - - @QField() - private String newValue; - - @QField(maxLength = 1000) - private String message; - - @QField(isEditable = false) - private Instant createDate; - - - - /*************************************************************************** - ** TableMetaDataCustomizer -- sets icon, record label, sections, and - ** registers PRE_UPDATE and PRE_DELETE customizers to enforce immutability. - ***************************************************************************/ - public static class TableMetaDataCustomizer implements MetaDataCustomizerInterface - { - - /*************************************************************************** - ** - ***************************************************************************/ - @Override - public QTableMetaData customizeMetaData(QInstance qInstance, QTableMetaData table) throws QException - { - table - .withIcon(new QIcon().withName("history")) - .withRecordLabelFormat("%s %s #%s") - .withRecordLabelFields("action", "entityType", "entityId") - .withSection(SectionFactory.defaultT1("id", "entityType", "entityId", "action")) - .withSection(new QFieldSection("details", new QIcon("text_snippet"), Tier.T2, - List.of("userId", "fieldName", "oldValue", "newValue", "message"))) - .withSection(SectionFactory.defaultT3("createDate")); - - /////////////////////////////////////////////////////////////////////////// - // register PRE_UPDATE and PRE_DELETE customizers to enforce immutability // - /////////////////////////////////////////////////////////////////////////// - table.withCustomizer(TableCustomizers.PRE_UPDATE_RECORD, new QCodeReference(PreventUpdateCustomizer.class)); - table.withCustomizer(TableCustomizers.PRE_DELETE_RECORD, new QCodeReference(PreventDeleteCustomizer.class)); - - return (table); - } - } - - - - /*************************************************************************** - ** PRE_UPDATE customizer that rejects all update attempts on audit log. - ***************************************************************************/ - public static class PreventUpdateCustomizer extends AbstractPreUpdateCustomizer - { - /*************************************************************************** - ** - ***************************************************************************/ - @Override - public List apply(List records) throws QException - { - if("true".equals(QContext.getQSession().getValue("gdprBypass"))) - { - return records; - } - throw new QUserFacingException("Audit log records cannot be modified or deleted"); - } - } - - - - /*************************************************************************** - ** PRE_DELETE customizer that rejects all delete attempts on audit log. - ***************************************************************************/ - public static class PreventDeleteCustomizer extends AbstractPreDeleteCustomizer - { - /*************************************************************************** - ** - ***************************************************************************/ - @Override - public List apply(List records) throws QException - { - if("true".equals(QContext.getQSession().getValue("gdprBypass"))) - { - return records; - } - throw new QUserFacingException("Audit log records cannot be modified or deleted"); - } - } - - - - /******************************************************************************* - ** Default constructor - *******************************************************************************/ - public AuditLog() - { - } - - - - /******************************************************************************* - ** Constructor that takes a QRecord - *******************************************************************************/ - public AuditLog(QRecord record) - { - populateFromQRecord(record); - } - - - - /******************************************************************************* - ** Getter for id - *******************************************************************************/ - public Integer getId() - { - return (this.id); - } - - - - /******************************************************************************* - ** Setter for id - *******************************************************************************/ - public void setId(Integer id) - { - this.id = id; - } - - - - /******************************************************************************* - ** Fluent setter for id - *******************************************************************************/ - public AuditLog withId(Integer id) - { - this.id = id; - return (this); - } - - - - /******************************************************************************* - ** Getter for entityType - *******************************************************************************/ - public Integer getEntityType() - { - return (this.entityType); - } - - - - /******************************************************************************* - ** Setter for entityType - *******************************************************************************/ - public void setEntityType(Integer entityType) - { - this.entityType = entityType; - } - - - - /******************************************************************************* - ** Fluent setter for entityType - *******************************************************************************/ - public AuditLog withEntityType(Integer entityType) - { - this.entityType = entityType; - return (this); - } - - - - /******************************************************************************* - ** Getter for entityId - *******************************************************************************/ - public Integer getEntityId() - { - return (this.entityId); - } - - - - /******************************************************************************* - ** Setter for entityId - *******************************************************************************/ - public void setEntityId(Integer entityId) - { - this.entityId = entityId; - } - - - - /******************************************************************************* - ** Fluent setter for entityId - *******************************************************************************/ - public AuditLog withEntityId(Integer entityId) - { - this.entityId = entityId; - return (this); - } - - - - /******************************************************************************* - ** Getter for action - *******************************************************************************/ - public Integer getAction() - { - return (this.action); - } - - - - /******************************************************************************* - ** Setter for action - *******************************************************************************/ - public void setAction(Integer action) - { - this.action = action; - } - - - - /******************************************************************************* - ** Fluent setter for action - *******************************************************************************/ - public AuditLog withAction(Integer action) - { - this.action = action; - return (this); - } - - - - /******************************************************************************* - ** Getter for userId - *******************************************************************************/ - public String getUserId() - { - return (this.userId); - } - - - - /******************************************************************************* - ** Setter for userId - *******************************************************************************/ - public void setUserId(String userId) - { - this.userId = userId; - } - - - - /******************************************************************************* - ** Fluent setter for userId - *******************************************************************************/ - public AuditLog withUserId(String userId) - { - this.userId = userId; - return (this); - } - - - - /******************************************************************************* - ** Getter for fieldName - *******************************************************************************/ - public String getFieldName() - { - return (this.fieldName); - } - - - - /******************************************************************************* - ** Setter for fieldName - *******************************************************************************/ - public void setFieldName(String fieldName) - { - this.fieldName = fieldName; - } - - - - /******************************************************************************* - ** Fluent setter for fieldName - *******************************************************************************/ - public AuditLog withFieldName(String fieldName) - { - this.fieldName = fieldName; - return (this); - } - - - - /******************************************************************************* - ** Getter for oldValue - *******************************************************************************/ - public String getOldValue() - { - return (this.oldValue); - } - - - - /******************************************************************************* - ** Setter for oldValue - *******************************************************************************/ - public void setOldValue(String oldValue) - { - this.oldValue = oldValue; - } - - - - /******************************************************************************* - ** Fluent setter for oldValue - *******************************************************************************/ - public AuditLog withOldValue(String oldValue) - { - this.oldValue = oldValue; - return (this); - } - - - - /******************************************************************************* - ** Getter for newValue - *******************************************************************************/ - public String getNewValue() - { - return (this.newValue); - } - - - - /******************************************************************************* - ** Setter for newValue - *******************************************************************************/ - public void setNewValue(String newValue) - { - this.newValue = newValue; - } - - - - /******************************************************************************* - ** Fluent setter for newValue - *******************************************************************************/ - public AuditLog withNewValue(String newValue) - { - this.newValue = newValue; - return (this); - } - - - - /******************************************************************************* - ** Getter for message - *******************************************************************************/ - public String getMessage() - { - return (this.message); - } - - - - /******************************************************************************* - ** Setter for message - *******************************************************************************/ - public void setMessage(String message) - { - this.message = message; - } - - - - /******************************************************************************* - ** Fluent setter for message - *******************************************************************************/ - public AuditLog withMessage(String message) - { - this.message = message; - return (this); - } - - - - /******************************************************************************* - ** Getter for createDate - *******************************************************************************/ - public Instant getCreateDate() - { - return (this.createDate); - } - - - - /******************************************************************************* - ** Setter for createDate - *******************************************************************************/ - public void setCreateDate(Instant createDate) - { - this.createDate = createDate; - } - - - - /******************************************************************************* - ** Fluent setter for createDate - *******************************************************************************/ - public AuditLog withCreateDate(Instant createDate) - { - this.createDate = createDate; - return (this); - } - -} diff --git a/src/main/java/com/kingsrook/qbits/crm/core/customizers/FormSubmissionAutoLinkCustomizer.java b/src/main/java/com/kingsrook/qbits/crm/core/customizers/FormSubmissionAutoLinkCustomizer.java index 3b6e144..15764e2 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/customizers/FormSubmissionAutoLinkCustomizer.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/customizers/FormSubmissionAutoLinkCustomizer.java @@ -1,7 +1,29 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** POST_INSERT customizer for form submissions. Auto-links contactId if a ** contact with a matching email address already exists. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.customizers; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/Attachment.java b/src/main/java/com/kingsrook/qbits/crm/core/model/Attachment.java deleted file mode 100644 index c51ca3e..0000000 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/Attachment.java +++ /dev/null @@ -1,388 +0,0 @@ -/******************************************************************************* - ** QRecord Entity for Attachment table - *******************************************************************************/ -package com.kingsrook.qbits.crm.core.model; - - -import java.time.Instant; -import com.kingsrook.qbits.crm.core.model.enums.CrmEntityType; -import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.model.data.QField; -import com.kingsrook.qqq.backend.core.model.data.QRecord; -import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; -import com.kingsrook.qqq.backend.core.model.metadata.QInstance; -import com.kingsrook.qqq.backend.core.model.metadata.fields.ValueTooLongBehavior; -import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon; -import com.kingsrook.qqq.backend.core.model.metadata.producers.MetaDataCustomizerInterface; -import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.QMetaDataProducingEntity; -import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.tables.SectionFactory; - - -/******************************************************************************* - ** QRecord Entity for Attachment table -- polymorphic file attachments linked - ** to any CRM entity via entityType + entityId. Insert-and-delete-only; no - ** modifyDate. Carries denormalized clientId for security lock. - *******************************************************************************/ -@QMetaDataProducingEntity( - produceTableMetaData = true, - tableMetaDataCustomizer = Attachment.TableMetaDataCustomizer.class -) -public class Attachment extends QRecordEntity -{ - public static final String TABLE_NAME = "crmAttachment"; - - - - /*************************************************************************** - ** - ***************************************************************************/ - public static class TableMetaDataCustomizer implements MetaDataCustomizerInterface - { - - /*************************************************************************** - ** - ***************************************************************************/ - @Override - public QTableMetaData customizeMetaData(QInstance qInstance, QTableMetaData table) throws QException - { - table - .withIcon(new QIcon().withName("attach_file")) - .withRecordLabelFormat("%s") - .withRecordLabelFields("fileName") - .withSection(SectionFactory.defaultT1("id", "entityType", "entityId", "fileName")) - .withSection(SectionFactory.defaultT2("fileType", "fileSizeBytes", "storageReference", "uploadedByUserId")) - .withSection(SectionFactory.defaultT3("createDate")); - - return (table); - } - } - - - - @QField(isEditable = false, isPrimaryKey = true) - private Integer id; - - @QField(isRequired = true, possibleValueSourceName = CrmEntityType.NAME) - private Integer entityType; - - @QField(isRequired = true) - private Integer entityId; - - @QField(isRequired = true, maxLength = 500, valueTooLongBehavior = ValueTooLongBehavior.ERROR) - private String fileName; - - @QField(maxLength = 100, valueTooLongBehavior = ValueTooLongBehavior.ERROR) - private String fileType; - - @QField() - private Long fileSizeBytes; - - @QField(isRequired = true, maxLength = 1000, valueTooLongBehavior = ValueTooLongBehavior.ERROR) - private String storageReference; - - @QField(isRequired = true) - private String uploadedByUserId; - - @QField(isEditable = false) - private Instant createDate; - - - - /******************************************************************************* - ** Default constructor - *******************************************************************************/ - public Attachment() - { - } - - - - /******************************************************************************* - ** Constructor that takes a QRecord - *******************************************************************************/ - public Attachment(QRecord record) - { - populateFromQRecord(record); - } - - - - /******************************************************************************* - ** Getter for id - *******************************************************************************/ - public Integer getId() - { - return (this.id); - } - - - - /******************************************************************************* - ** Setter for id - *******************************************************************************/ - public void setId(Integer id) - { - this.id = id; - } - - - - /******************************************************************************* - ** Fluent setter for id - *******************************************************************************/ - public Attachment withId(Integer id) - { - this.id = id; - return (this); - } - - - - /******************************************************************************* - ** Getter for entityType - *******************************************************************************/ - public Integer getEntityType() - { - return (this.entityType); - } - - - - /******************************************************************************* - ** Setter for entityType - *******************************************************************************/ - public void setEntityType(Integer entityType) - { - this.entityType = entityType; - } - - - - /******************************************************************************* - ** Fluent setter for entityType - *******************************************************************************/ - public Attachment withEntityType(Integer entityType) - { - this.entityType = entityType; - return (this); - } - - - - /******************************************************************************* - ** Getter for entityId - *******************************************************************************/ - public Integer getEntityId() - { - return (this.entityId); - } - - - - /******************************************************************************* - ** Setter for entityId - *******************************************************************************/ - public void setEntityId(Integer entityId) - { - this.entityId = entityId; - } - - - - /******************************************************************************* - ** Fluent setter for entityId - *******************************************************************************/ - public Attachment withEntityId(Integer entityId) - { - this.entityId = entityId; - return (this); - } - - - - /******************************************************************************* - ** Getter for fileName - *******************************************************************************/ - public String getFileName() - { - return (this.fileName); - } - - - - /******************************************************************************* - ** Setter for fileName - *******************************************************************************/ - public void setFileName(String fileName) - { - this.fileName = fileName; - } - - - - /******************************************************************************* - ** Fluent setter for fileName - *******************************************************************************/ - public Attachment withFileName(String fileName) - { - this.fileName = fileName; - return (this); - } - - - - /******************************************************************************* - ** Getter for fileType - *******************************************************************************/ - public String getFileType() - { - return (this.fileType); - } - - - - /******************************************************************************* - ** Setter for fileType - *******************************************************************************/ - public void setFileType(String fileType) - { - this.fileType = fileType; - } - - - - /******************************************************************************* - ** Fluent setter for fileType - *******************************************************************************/ - public Attachment withFileType(String fileType) - { - this.fileType = fileType; - return (this); - } - - - - /******************************************************************************* - ** Getter for fileSizeBytes - *******************************************************************************/ - public Long getFileSizeBytes() - { - return (this.fileSizeBytes); - } - - - - /******************************************************************************* - ** Setter for fileSizeBytes - *******************************************************************************/ - public void setFileSizeBytes(Long fileSizeBytes) - { - this.fileSizeBytes = fileSizeBytes; - } - - - - /******************************************************************************* - ** Fluent setter for fileSizeBytes - *******************************************************************************/ - public Attachment withFileSizeBytes(Long fileSizeBytes) - { - this.fileSizeBytes = fileSizeBytes; - return (this); - } - - - - /******************************************************************************* - ** Getter for storageReference - *******************************************************************************/ - public String getStorageReference() - { - return (this.storageReference); - } - - - - /******************************************************************************* - ** Setter for storageReference - *******************************************************************************/ - public void setStorageReference(String storageReference) - { - this.storageReference = storageReference; - } - - - - /******************************************************************************* - ** Fluent setter for storageReference - *******************************************************************************/ - public Attachment withStorageReference(String storageReference) - { - this.storageReference = storageReference; - return (this); - } - - - - /******************************************************************************* - ** Getter for uploadedByUserId - *******************************************************************************/ - public String getUploadedByUserId() - { - return (this.uploadedByUserId); - } - - - - /******************************************************************************* - ** Setter for uploadedByUserId - *******************************************************************************/ - public void setUploadedByUserId(String uploadedByUserId) - { - this.uploadedByUserId = uploadedByUserId; - } - - - - /******************************************************************************* - ** Fluent setter for uploadedByUserId - *******************************************************************************/ - public Attachment withUploadedByUserId(String uploadedByUserId) - { - this.uploadedByUserId = uploadedByUserId; - return (this); - } - - - - /******************************************************************************* - ** Getter for createDate - *******************************************************************************/ - public Instant getCreateDate() - { - return (this.createDate); - } - - - - /******************************************************************************* - ** Setter for createDate - *******************************************************************************/ - public void setCreateDate(Instant createDate) - { - this.createDate = createDate; - } - - - - /******************************************************************************* - ** Fluent setter for createDate - *******************************************************************************/ - public Attachment withCreateDate(Instant createDate) - { - this.createDate = createDate; - return (this); - } - -} diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/Company.java b/src/main/java/com/kingsrook/qbits/crm/core/model/Company.java index 44eefe6..76fac1f 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/Company.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/Company.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for Company table *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; @@ -46,15 +68,12 @@ import com.kingsrook.qqq.backend.core.utils.collections.MutableList; childRecordListWidget = @ChildRecordListWidget(label = "Contacts", enabled = true, maxRows = 50)), @ChildTable(childTableEntityClass = Deal.class, joinFieldName = "companyId", childJoin = @ChildJoin(enabled = true), - childRecordListWidget = @ChildRecordListWidget(label = "Deals", enabled = true, maxRows = 25)), - @ChildTable(childTableEntityClass = CompanyTag.class, joinFieldName = "companyId", - childJoin = @ChildJoin(enabled = true), - childRecordListWidget = @ChildRecordListWidget(label = "Tags", enabled = true, maxRows = 50)) + childRecordListWidget = @ChildRecordListWidget(label = "Deals", enabled = true, maxRows = 25)) } ) public class Company extends QRecordEntity { - public static final String TABLE_NAME = "crmCompany"; + public static final String TABLE_NAME = "crm_company"; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/CompanyTag.java b/src/main/java/com/kingsrook/qbits/crm/core/model/CompanyTag.java deleted file mode 100644 index c7dcc35..0000000 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/CompanyTag.java +++ /dev/null @@ -1,216 +0,0 @@ -/******************************************************************************* - ** QRecord Entity for CompanyTag table - *******************************************************************************/ -package com.kingsrook.qbits.crm.core.model; - - -import java.time.Instant; -import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.model.data.QField; -import com.kingsrook.qqq.backend.core.model.data.QRecord; -import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; -import com.kingsrook.qqq.backend.core.model.metadata.QInstance; -import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon; -import com.kingsrook.qqq.backend.core.model.metadata.producers.MetaDataCustomizerInterface; -import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.QMetaDataProducingEntity; -import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.tables.SectionFactory; -import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; - - -/******************************************************************************* - ** QRecord Entity for CompanyTag junction table -- many-to-many link between - ** companies and tags. - *******************************************************************************/ -@QMetaDataProducingEntity( - produceTableMetaData = true, - tableMetaDataCustomizer = CompanyTag.TableMetaDataCustomizer.class -) -public class CompanyTag extends QRecordEntity -{ - public static final String TABLE_NAME = "crmCompanyTag"; - - - - /*************************************************************************** - ** - ***************************************************************************/ - public static class TableMetaDataCustomizer implements MetaDataCustomizerInterface - { - - /*************************************************************************** - ** - ***************************************************************************/ - @Override - public QTableMetaData customizeMetaData(QInstance qInstance, QTableMetaData table) throws QException - { - table - .withIcon(new QIcon().withName("label")) - .withRecordLabelFormat("Company %s - Tag %s") - .withRecordLabelFields("companyId", "tagId") - .withUniqueKey(new UniqueKey("companyId", "tagId")) - .withSection(SectionFactory.defaultT1("id", "companyId", "tagId")) - .withSection(SectionFactory.defaultT3("createDate")); - - return (table); - } - } - - - - @QField(isEditable = false, isPrimaryKey = true) - private Integer id; - - @QField(isRequired = true, possibleValueSourceName = Company.TABLE_NAME) - private Integer companyId; - - @QField(isRequired = true, possibleValueSourceName = Tag.TABLE_NAME) - private Integer tagId; - - @QField(isEditable = false) - private Instant createDate; - - - - /******************************************************************************* - ** Default constructor - *******************************************************************************/ - public CompanyTag() - { - } - - - - /******************************************************************************* - ** Constructor that takes a QRecord - *******************************************************************************/ - public CompanyTag(QRecord record) - { - populateFromQRecord(record); - } - - - - /******************************************************************************* - ** Getter for id - *******************************************************************************/ - public Integer getId() - { - return (this.id); - } - - - - /******************************************************************************* - ** Setter for id - *******************************************************************************/ - public void setId(Integer id) - { - this.id = id; - } - - - - /******************************************************************************* - ** Fluent setter for id - *******************************************************************************/ - public CompanyTag withId(Integer id) - { - this.id = id; - return (this); - } - - - - /******************************************************************************* - ** Getter for companyId - *******************************************************************************/ - public Integer getCompanyId() - { - return (this.companyId); - } - - - - /******************************************************************************* - ** Setter for companyId - *******************************************************************************/ - public void setCompanyId(Integer companyId) - { - this.companyId = companyId; - } - - - - /******************************************************************************* - ** Fluent setter for companyId - *******************************************************************************/ - public CompanyTag withCompanyId(Integer companyId) - { - this.companyId = companyId; - return (this); - } - - - - /******************************************************************************* - ** Getter for tagId - *******************************************************************************/ - public Integer getTagId() - { - return (this.tagId); - } - - - - /******************************************************************************* - ** Setter for tagId - *******************************************************************************/ - public void setTagId(Integer tagId) - { - this.tagId = tagId; - } - - - - /******************************************************************************* - ** Fluent setter for tagId - *******************************************************************************/ - public CompanyTag withTagId(Integer tagId) - { - this.tagId = tagId; - return (this); - } - - - - /******************************************************************************* - ** Getter for createDate - *******************************************************************************/ - public Instant getCreateDate() - { - return (this.createDate); - } - - - - /******************************************************************************* - ** Setter for createDate - *******************************************************************************/ - public void setCreateDate(Instant createDate) - { - this.createDate = createDate; - } - - - - /******************************************************************************* - ** Fluent setter for createDate - *******************************************************************************/ - public CompanyTag withCreateDate(Instant createDate) - { - this.createDate = createDate; - return (this); - } - -} diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/ConsentRecord.java b/src/main/java/com/kingsrook/qbits/crm/core/model/ConsentRecord.java index 71b953e..878618c 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/ConsentRecord.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/ConsentRecord.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for ConsentRecord table *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; @@ -37,7 +59,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.SectionFactory; ) public class ConsentRecord extends QRecordEntity { - public static final String TABLE_NAME = "crmConsentRecord"; + public static final String TABLE_NAME = "crm_consent_record"; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/Contact.java b/src/main/java/com/kingsrook/qbits/crm/core/model/Contact.java index 6900598..8f32546 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/Contact.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/Contact.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for Contact table *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; @@ -33,7 +55,7 @@ import com.kingsrook.qqq.backend.core.utils.collections.MutableList; /******************************************************************************* ** QRecord Entity for Contact table -- the primary person record in the CRM. - ** Contacts are linked to companies, activities, deals, and tags. + ** Contacts are linked to companies, activities and deals. *******************************************************************************/ @QMetaDataProducingEntity( producePossibleValueSource = true, @@ -46,9 +68,6 @@ import com.kingsrook.qqq.backend.core.utils.collections.MutableList; @ChildTable(childTableEntityClass = DealContact.class, joinFieldName = "contactId", childJoin = @ChildJoin(enabled = true), childRecordListWidget = @ChildRecordListWidget(label = "Deals", enabled = true, maxRows = 25)), - @ChildTable(childTableEntityClass = ContactTag.class, joinFieldName = "contactId", - childJoin = @ChildJoin(enabled = true), - childRecordListWidget = @ChildRecordListWidget(label = "Tags", enabled = true, maxRows = 50)), @ChildTable(childTableEntityClass = ConsentRecord.class, joinFieldName = "contactId", childJoin = @ChildJoin(enabled = true), childRecordListWidget = @ChildRecordListWidget(label = "Consent Records", enabled = true, maxRows = 25)) @@ -56,7 +75,7 @@ import com.kingsrook.qqq.backend.core.utils.collections.MutableList; ) public class Contact extends QRecordEntity { - public static final String TABLE_NAME = "crmContact"; + public static final String TABLE_NAME = "crm_contact"; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/ContactTag.java b/src/main/java/com/kingsrook/qbits/crm/core/model/ContactTag.java deleted file mode 100644 index bc08412..0000000 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/ContactTag.java +++ /dev/null @@ -1,216 +0,0 @@ -/******************************************************************************* - ** QRecord Entity for ContactTag table - *******************************************************************************/ -package com.kingsrook.qbits.crm.core.model; - - -import java.time.Instant; -import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.model.data.QField; -import com.kingsrook.qqq.backend.core.model.data.QRecord; -import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; -import com.kingsrook.qqq.backend.core.model.metadata.QInstance; -import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon; -import com.kingsrook.qqq.backend.core.model.metadata.producers.MetaDataCustomizerInterface; -import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.QMetaDataProducingEntity; -import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.tables.SectionFactory; -import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; - - -/******************************************************************************* - ** QRecord Entity for ContactTag junction table -- many-to-many link between - ** contacts and tags. - *******************************************************************************/ -@QMetaDataProducingEntity( - produceTableMetaData = true, - tableMetaDataCustomizer = ContactTag.TableMetaDataCustomizer.class -) -public class ContactTag extends QRecordEntity -{ - public static final String TABLE_NAME = "crmContactTag"; - - - - /*************************************************************************** - ** - ***************************************************************************/ - public static class TableMetaDataCustomizer implements MetaDataCustomizerInterface - { - - /*************************************************************************** - ** - ***************************************************************************/ - @Override - public QTableMetaData customizeMetaData(QInstance qInstance, QTableMetaData table) throws QException - { - table - .withIcon(new QIcon().withName("label")) - .withRecordLabelFormat("Contact %s - Tag %s") - .withRecordLabelFields("contactId", "tagId") - .withUniqueKey(new UniqueKey("contactId", "tagId")) - .withSection(SectionFactory.defaultT1("id", "contactId", "tagId")) - .withSection(SectionFactory.defaultT3("createDate")); - - return (table); - } - } - - - - @QField(isEditable = false, isPrimaryKey = true) - private Integer id; - - @QField(isRequired = true, possibleValueSourceName = Contact.TABLE_NAME) - private Integer contactId; - - @QField(isRequired = true, possibleValueSourceName = Tag.TABLE_NAME) - private Integer tagId; - - @QField(isEditable = false) - private Instant createDate; - - - - /******************************************************************************* - ** Default constructor - *******************************************************************************/ - public ContactTag() - { - } - - - - /******************************************************************************* - ** Constructor that takes a QRecord - *******************************************************************************/ - public ContactTag(QRecord record) - { - populateFromQRecord(record); - } - - - - /******************************************************************************* - ** Getter for id - *******************************************************************************/ - public Integer getId() - { - return (this.id); - } - - - - /******************************************************************************* - ** Setter for id - *******************************************************************************/ - public void setId(Integer id) - { - this.id = id; - } - - - - /******************************************************************************* - ** Fluent setter for id - *******************************************************************************/ - public ContactTag withId(Integer id) - { - this.id = id; - return (this); - } - - - - /******************************************************************************* - ** Getter for contactId - *******************************************************************************/ - public Integer getContactId() - { - return (this.contactId); - } - - - - /******************************************************************************* - ** Setter for contactId - *******************************************************************************/ - public void setContactId(Integer contactId) - { - this.contactId = contactId; - } - - - - /******************************************************************************* - ** Fluent setter for contactId - *******************************************************************************/ - public ContactTag withContactId(Integer contactId) - { - this.contactId = contactId; - return (this); - } - - - - /******************************************************************************* - ** Getter for tagId - *******************************************************************************/ - public Integer getTagId() - { - return (this.tagId); - } - - - - /******************************************************************************* - ** Setter for tagId - *******************************************************************************/ - public void setTagId(Integer tagId) - { - this.tagId = tagId; - } - - - - /******************************************************************************* - ** Fluent setter for tagId - *******************************************************************************/ - public ContactTag withTagId(Integer tagId) - { - this.tagId = tagId; - return (this); - } - - - - /******************************************************************************* - ** Getter for createDate - *******************************************************************************/ - public Instant getCreateDate() - { - return (this.createDate); - } - - - - /******************************************************************************* - ** Setter for createDate - *******************************************************************************/ - public void setCreateDate(Instant createDate) - { - this.createDate = createDate; - } - - - - /******************************************************************************* - ** Fluent setter for createDate - *******************************************************************************/ - public ContactTag withCreateDate(Instant createDate) - { - this.createDate = createDate; - return (this); - } - -} diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/Currency.java b/src/main/java/com/kingsrook/qbits/crm/core/model/Currency.java index 6921d7c..49d3c61 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/Currency.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/Currency.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for Currency table *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; @@ -32,7 +54,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; ) public class Currency extends QRecordEntity { - public static final String TABLE_NAME = "crmCurrency"; + public static final String TABLE_NAME = "crm_currency"; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/EmailList.java b/src/main/java/com/kingsrook/qbits/crm/core/model/EmailList.java index 9fb6878..7debc83 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/EmailList.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/EmailList.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for EmailList table *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; @@ -30,7 +52,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; ) public class EmailList extends QRecordEntity { - public static final String TABLE_NAME = "crmEmailList"; + public static final String TABLE_NAME = "crm_email_list"; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/EmailListMember.java b/src/main/java/com/kingsrook/qbits/crm/core/model/EmailListMember.java index 24d9aaf..b1ebf45 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/EmailListMember.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/EmailListMember.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for EmailListMember table *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; @@ -33,7 +55,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; ) public class EmailListMember extends QRecordEntity { - public static final String TABLE_NAME = "crmEmailListMember"; + public static final String TABLE_NAME = "crm_email_list_member"; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/FormSubmission.java b/src/main/java/com/kingsrook/qbits/crm/core/model/FormSubmission.java index 04fb77c..5e1bb20 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/FormSubmission.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/FormSubmission.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for FormSubmission table *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; @@ -35,7 +57,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.Tier; ) public class FormSubmission extends QRecordEntity { - public static final String TABLE_NAME = "crmFormSubmission"; + public static final String TABLE_NAME = "crm_form_submission"; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/Industry.java b/src/main/java/com/kingsrook/qbits/crm/core/model/Industry.java index 860b0e9..bbd7dbb 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/Industry.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/Industry.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for Industry table *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; @@ -30,7 +52,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; ) public class Industry extends QRecordEntity { - public static final String TABLE_NAME = "crmIndustry"; + public static final String TABLE_NAME = "crm_industry"; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/LeadSource.java b/src/main/java/com/kingsrook/qbits/crm/core/model/LeadSource.java index 5f71f90..ef4d837 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/LeadSource.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/LeadSource.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for LeadSource table *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; @@ -30,7 +52,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; ) public class LeadSource extends QRecordEntity { - public static final String TABLE_NAME = "crmLeadSource"; + public static final String TABLE_NAME = "crm_lead_source"; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/LifecycleStage.java b/src/main/java/com/kingsrook/qbits/crm/core/model/LifecycleStage.java index ad79aed..c80815c 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/LifecycleStage.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/LifecycleStage.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for LifecycleStage table *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; @@ -30,7 +52,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; ) public class LifecycleStage extends QRecordEntity { - public static final String TABLE_NAME = "crmLifecycleStage"; + public static final String TABLE_NAME = "crm_lifecycle_stage"; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/Tag.java b/src/main/java/com/kingsrook/qbits/crm/core/model/Tag.java deleted file mode 100644 index 9bcbcec..0000000 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/Tag.java +++ /dev/null @@ -1,252 +0,0 @@ -/******************************************************************************* - ** QRecord Entity for Tag table - *******************************************************************************/ -package com.kingsrook.qbits.crm.core.model; - - -import java.time.Instant; -import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.model.data.QField; -import com.kingsrook.qqq.backend.core.model.data.QRecord; -import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; -import com.kingsrook.qqq.backend.core.model.metadata.QInstance; -import com.kingsrook.qqq.backend.core.model.metadata.fields.ValueTooLongBehavior; -import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon; -import com.kingsrook.qqq.backend.core.model.metadata.producers.MetaDataCustomizerInterface; -import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.QMetaDataProducingEntity; -import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.tables.SectionFactory; -import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; - - -/******************************************************************************* - ** QRecord Entity for Tag table -- freeform tags that can be applied to - ** contacts, companies, and deals via junction tables. - *******************************************************************************/ -@QMetaDataProducingEntity( - producePossibleValueSource = true, - produceTableMetaData = true, - tableMetaDataCustomizer = Tag.TableMetaDataCustomizer.class -) -public class Tag extends QRecordEntity -{ - public static final String TABLE_NAME = "crmTag"; - - - - /*************************************************************************** - ** - ***************************************************************************/ - public static class TableMetaDataCustomizer implements MetaDataCustomizerInterface - { - - /*************************************************************************** - ** - ***************************************************************************/ - @Override - public QTableMetaData customizeMetaData(QInstance qInstance, QTableMetaData table) throws QException - { - table - .withIcon(new QIcon().withName("label")) - .withRecordLabelFormat("%s") - .withRecordLabelFields("name") - .withUniqueKey(new UniqueKey("name")) - .withSection(SectionFactory.defaultT1("id", "name", "color")) - .withSection(SectionFactory.defaultT3("createDate", "modifyDate")); - - return (table); - } - } - - - - @QField(isEditable = false, isPrimaryKey = true) - private Integer id; - - @QField(isRequired = true, maxLength = 100, valueTooLongBehavior = ValueTooLongBehavior.ERROR) - private String name; - - @QField(maxLength = 7, valueTooLongBehavior = ValueTooLongBehavior.ERROR) - private String color; - - @QField(isEditable = false) - private Instant createDate; - - @QField(isEditable = false) - private Instant modifyDate; - - - - /******************************************************************************* - ** Default constructor - *******************************************************************************/ - public Tag() - { - } - - - - /******************************************************************************* - ** Constructor that takes a QRecord - *******************************************************************************/ - public Tag(QRecord record) - { - populateFromQRecord(record); - } - - - - /******************************************************************************* - ** Getter for id - *******************************************************************************/ - public Integer getId() - { - return (this.id); - } - - - - /******************************************************************************* - ** Setter for id - *******************************************************************************/ - public void setId(Integer id) - { - this.id = id; - } - - - - /******************************************************************************* - ** Fluent setter for id - *******************************************************************************/ - public Tag withId(Integer id) - { - this.id = id; - return (this); - } - - - - /******************************************************************************* - ** Getter for name - *******************************************************************************/ - public String getName() - { - return (this.name); - } - - - - /******************************************************************************* - ** Setter for name - *******************************************************************************/ - public void setName(String name) - { - this.name = name; - } - - - - /******************************************************************************* - ** Fluent setter for name - *******************************************************************************/ - public Tag withName(String name) - { - this.name = name; - return (this); - } - - - - /******************************************************************************* - ** Getter for color - *******************************************************************************/ - public String getColor() - { - return (this.color); - } - - - - /******************************************************************************* - ** Setter for color - *******************************************************************************/ - public void setColor(String color) - { - this.color = color; - } - - - - /******************************************************************************* - ** Fluent setter for color - *******************************************************************************/ - public Tag withColor(String color) - { - this.color = color; - return (this); - } - - - - /******************************************************************************* - ** Getter for createDate - *******************************************************************************/ - public Instant getCreateDate() - { - return (this.createDate); - } - - - - /******************************************************************************* - ** Setter for createDate - *******************************************************************************/ - public void setCreateDate(Instant createDate) - { - this.createDate = createDate; - } - - - - /******************************************************************************* - ** Fluent setter for createDate - *******************************************************************************/ - public Tag withCreateDate(Instant createDate) - { - this.createDate = createDate; - return (this); - } - - - - /******************************************************************************* - ** Getter for modifyDate - *******************************************************************************/ - public Instant getModifyDate() - { - return (this.modifyDate); - } - - - - /******************************************************************************* - ** Setter for modifyDate - *******************************************************************************/ - public void setModifyDate(Instant modifyDate) - { - this.modifyDate = modifyDate; - } - - - - /******************************************************************************* - ** Fluent setter for modifyDate - *******************************************************************************/ - public Tag withModifyDate(Instant modifyDate) - { - this.modifyDate = modifyDate; - return (this); - } - -} diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmActivityPriority.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmActivityPriority.java index 7e5b83b..35a2088 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmActivityPriority.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmActivityPriority.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM activity priority levels. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmAssignStrategy.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmAssignStrategy.java index 15deb88..9cd1381 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmAssignStrategy.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmAssignStrategy.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM assignment strategies. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmAssignableEntity.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmAssignableEntity.java index ef37f95..edf919c 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmAssignableEntity.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmAssignableEntity.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM assignable entity types. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmAuditAction.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmAuditAction.java deleted file mode 100644 index 7d2c3db..0000000 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmAuditAction.java +++ /dev/null @@ -1,113 +0,0 @@ -/******************************************************************************* - ** Possible value source enum for CRM audit log actions. - *******************************************************************************/ -package com.kingsrook.qbits.crm.core.model.enums; - - -import java.util.Objects; -import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.PossibleValueEnum; -import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.QMetaDataProducingPossibleValueEnum; - - -/******************************************************************************* - ** Enum of CRM audit log actions tracked for entity changes. - *******************************************************************************/ -@QMetaDataProducingPossibleValueEnum() -public enum CrmAuditAction implements PossibleValueEnum -{ - CREATED(1, "Created"), - UPDATED(2, "Updated"), - DELETED(3, "Deleted"), - STAGE_CHANGED(4, "Stage Changed"), - OWNER_CHANGED(5, "Owner Changed"), - SCORE_CHANGED(6, "Score Changed"), - MERGED(7, "Merged"), - CONSENT_CHANGED(8, "Consent Changed"), - TAG_CHANGED(9, "Tag Changed"), - ENROLLED(10, "Enrolled"), - UNENROLLED(11, "Unenrolled"), - IMPORTED(12, "Imported"), - ANONYMIZED(13, "Anonymized"), - FORM_CONVERTED(14, "Form Converted"); - - private final Integer id; - private final String label; - - public static final String NAME = "CrmAuditAction"; - - - - /******************************************************************************* - ** Constructor - *******************************************************************************/ - CrmAuditAction(Integer id, String label) - { - this.id = id; - this.label = label; - } - - - - /******************************************************************************* - ** Get instance by id - *******************************************************************************/ - public static CrmAuditAction getById(Integer id) - { - if(id == null) - { - return (null); - } - - for(CrmAuditAction value : CrmAuditAction.values()) - { - if(Objects.equals(value.id, id)) - { - return (value); - } - } - - return (null); - } - - - - /******************************************************************************* - ** Getter for id - *******************************************************************************/ - public Integer getId() - { - return id; - } - - - - /******************************************************************************* - ** Getter for label - *******************************************************************************/ - public String getLabel() - { - return label; - } - - - - /******************************************************************************* - ** - *******************************************************************************/ - @Override - public Integer getPossibleValueId() - { - return (getId()); - } - - - - /******************************************************************************* - ** - *******************************************************************************/ - @Override - public String getPossibleValueLabel() - { - return (getLabel()); - } -} diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmBounceType.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmBounceType.java index b423ef3..491a869 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmBounceType.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmBounceType.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM email bounce types. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmCompanyType.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmCompanyType.java index a133e71..e528445 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmCompanyType.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmCompanyType.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM company types. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmConsentStatus.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmConsentStatus.java index 154d28e..1941592 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmConsentStatus.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmConsentStatus.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM consent statuses. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmConsentType.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmConsentType.java index 092c407..86e8c35 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmConsentType.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmConsentType.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM consent types. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmDealPriority.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmDealPriority.java index 7e446d1..ad0d64a 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmDealPriority.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmDealPriority.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM deal priority levels. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmDirection.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmDirection.java index 922bc4a..ef16ac2 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmDirection.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmDirection.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM direction (inbound/outbound). *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmEmailStatus.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmEmailStatus.java index d12b155..ebb1e67 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmEmailStatus.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmEmailStatus.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM email statuses. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmEnrollmentStatus.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmEnrollmentStatus.java index e8b1726..61289da 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmEnrollmentStatus.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmEnrollmentStatus.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM sequence enrollment statuses. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmEntityType.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmEntityType.java index ef219f3..b115d10 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmEntityType.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmEntityType.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM entity types. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmFormConversionStatus.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmFormConversionStatus.java index 7e4e1d2..12a947b 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmFormConversionStatus.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmFormConversionStatus.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM form conversion statuses. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmFormType.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmFormType.java index 397ee5a..e866bcf 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmFormType.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmFormType.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM form types. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmGoalPeriod.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmGoalPeriod.java index 4779d3a..7108e0a 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmGoalPeriod.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmGoalPeriod.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM goal periods. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmLegalBasis.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmLegalBasis.java index b80ceb3..cfc1e88 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmLegalBasis.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmLegalBasis.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM legal basis types (GDPR). *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmListMemberStatus.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmListMemberStatus.java index 4c7c77c..32e27de 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmListMemberStatus.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmListMemberStatus.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM list member statuses. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmParticipantRole.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmParticipantRole.java index 6fb233f..efcbe76 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmParticipantRole.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmParticipantRole.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM activity participant roles. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmScorableEntity.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmScorableEntity.java index 2fc27b0..553c585 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmScorableEntity.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmScorableEntity.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM scorable entity types. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmScoreOperator.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmScoreOperator.java index df3438c..c00cd03 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmScoreOperator.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmScoreOperator.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM scoring rule operators. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmSequenceStepType.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmSequenceStepType.java index 8265a4c..4dee366 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmSequenceStepType.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmSequenceStepType.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM sequence step types. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmSyncStatus.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmSyncStatus.java index af515a3..e6dee23 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmSyncStatus.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmSyncStatus.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM sync statuses. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmWinLossType.java b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmWinLossType.java index cec6f82..1f53ca1 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmWinLossType.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/model/enums/CrmWinLossType.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Possible value source enum for CRM deal win/loss types. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/processes/BulkAddTagProcess.java b/src/main/java/com/kingsrook/qbits/crm/core/processes/BulkAddTagProcess.java deleted file mode 100644 index f7f54ed..0000000 --- a/src/main/java/com/kingsrook/qbits/crm/core/processes/BulkAddTagProcess.java +++ /dev/null @@ -1,115 +0,0 @@ -/******************************************************************************* - ** Bulk action process to add a tag to selected contact records. Inserts a - ** junction row in crmContactTag if one does not already exist. - *******************************************************************************/ -package com.kingsrook.qbits.crm.core.processes; - - -import java.util.List; -import com.kingsrook.qbits.crm.core.model.Contact; -import com.kingsrook.qbits.crm.core.model.ContactTag; -import com.kingsrook.qbits.crm.core.model.Tag; -import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; -import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; -import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; -import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface; -import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; -import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput; -import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; -import com.kingsrook.qqq.backend.core.model.data.QRecord; -import com.kingsrook.qqq.backend.core.model.metadata.QInstance; -import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; -import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType; -import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon; -import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; - - -/******************************************************************************* - ** MetaDataProducer + BackendStep for bulk-adding a tag to contacts. - ** For each selected record, inserts a crmContactTag junction row if one - ** does not already exist for that contactId + tagId combination. - *******************************************************************************/ -public class BulkAddTagProcess implements BackendStep, MetaDataProducerInterface -{ - public static final String NAME = "bulkAddTag"; - - - - /******************************************************************************* - ** Produce the process metadata. - *******************************************************************************/ - @Override - public QProcessMetaData produce(QInstance qInstance) throws QException - { - return new QProcessMetaData() - .withName(NAME) - .withLabel("Bulk Add Tag") - .withTableName(Contact.TABLE_NAME) - .withIcon(new QIcon().withName("label")) - .withStepList(List.of( - new QBackendStepMetaData() - .withName("execute") - .withCode(new QCodeReference(BulkAddTagProcess.class)) - .withInputData(new QFunctionInputMetaData().withFieldList(List.of( - new QFieldMetaData("tagId", QFieldType.INTEGER).withIsRequired(true).withPossibleValueSourceName(Tag.TABLE_NAME), - new QFieldMetaData("recordIds", QFieldType.STRING).withIsRequired(true).withLabel("Record IDs (comma-separated)") - ))) - )); - } - - - - /******************************************************************************* - ** Execute: for each record id, insert a junction row if not exists. - *******************************************************************************/ - @Override - public void run(RunBackendStepInput input, RunBackendStepOutput output) throws QException - { - Integer tagId = input.getValueInteger("tagId"); - String recordIds = input.getValueString("recordIds"); - - Integer addedCount = 0; - Integer skippedCount = 0; - - for(String idStr : recordIds.split(",")) - { - Integer contactId = Integer.parseInt(idStr.trim()); - - ///////////////////////////////////////////////////////////// - // check if the junction row already exists // - ///////////////////////////////////////////////////////////// - QueryOutput existingTags = new QueryAction().execute( - new QueryInput(ContactTag.TABLE_NAME) - .withFilter(new QQueryFilter() - .withCriteria(new QFilterCriteria("contactId", QCriteriaOperator.EQUALS, contactId)) - .withCriteria(new QFilterCriteria("tagId", QCriteriaOperator.EQUALS, tagId)))); - - if(existingTags.getRecords().isEmpty()) - { - new InsertAction().execute( - new InsertInput(ContactTag.TABLE_NAME).withRecordEntity( - new ContactTag() - .withContactId(contactId) - .withTagId(tagId))); - addedCount++; - } - else - { - skippedCount++; - } - } - - output.addValue("addedCount", addedCount); - output.addValue("skippedCount", skippedCount); - } - -} diff --git a/src/main/java/com/kingsrook/qbits/crm/core/processes/BulkAssignOwnerProcess.java b/src/main/java/com/kingsrook/qbits/crm/core/processes/BulkAssignOwnerProcess.java index 2de673f..6990c36 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/processes/BulkAssignOwnerProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/processes/BulkAssignOwnerProcess.java @@ -1,7 +1,29 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Bulk action process to assign a new owner to selected records. Works on ** any table that has an ownerUserId field. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.processes; @@ -32,7 +54,7 @@ import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwith *******************************************************************************/ public class BulkAssignOwnerProcess implements MetaDataProducerInterface { - public static final String NAME = "bulkAssignOwner"; + public static final String NAME = "crm_bulk_assign_owner"; @@ -71,8 +93,6 @@ public class BulkAssignOwnerProcess implements MetaDataProducerInterface -{ - public static final String NAME = "bulkRemoveTag"; - - - - /******************************************************************************* - ** Produce the process metadata. - *******************************************************************************/ - @Override - public QProcessMetaData produce(QInstance qInstance) throws QException - { - return new QProcessMetaData() - .withName(NAME) - .withLabel("Bulk Remove Tag") - .withTableName(Contact.TABLE_NAME) - .withIcon(new QIcon().withName("label_off")) - .withStepList(List.of( - new QBackendStepMetaData() - .withName("execute") - .withCode(new QCodeReference(BulkRemoveTagProcess.class)) - .withInputData(new QFunctionInputMetaData().withFieldList(List.of( - new QFieldMetaData("tagId", QFieldType.INTEGER).withIsRequired(true).withPossibleValueSourceName(Tag.TABLE_NAME), - new QFieldMetaData("recordIds", QFieldType.STRING).withIsRequired(true).withLabel("Record IDs (comma-separated)") - ))) - )); - } - - - - /******************************************************************************* - ** Execute: for each record id, delete the junction row if it exists. - *******************************************************************************/ - @Override - public void run(RunBackendStepInput input, RunBackendStepOutput output) throws QException - { - Integer tagId = input.getValueInteger("tagId"); - String recordIds = input.getValueString("recordIds"); - - Integer removedCount = 0; - Integer skippedCount = 0; - - for(String idStr : recordIds.split(",")) - { - Integer contactId = Integer.parseInt(idStr.trim()); - - ///////////////////////////////////////////////////////////// - // find the junction row // - ///////////////////////////////////////////////////////////// - QueryOutput existingTags = new QueryAction().execute( - new QueryInput(ContactTag.TABLE_NAME) - .withFilter(new QQueryFilter() - .withCriteria(new QFilterCriteria("contactId", QCriteriaOperator.EQUALS, contactId)) - .withCriteria(new QFilterCriteria("tagId", QCriteriaOperator.EQUALS, tagId)))); - - if(!existingTags.getRecords().isEmpty()) - { - QRecord tagRecord = existingTags.getRecords().get(0); - new DeleteAction().execute( - new DeleteInput(ContactTag.TABLE_NAME) - .withPrimaryKeys(List.of(tagRecord.getValueInteger("id")))); - removedCount++; - } - else - { - skippedCount++; - } - } - - output.addValue("removedCount", removedCount); - output.addValue("skippedCount", skippedCount); - } - -} diff --git a/src/main/java/com/kingsrook/qbits/crm/core/processes/ConvertFormToContactProcess.java b/src/main/java/com/kingsrook/qbits/crm/core/processes/ConvertFormToContactProcess.java index 7bbf9a5..0ac000a 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/processes/ConvertFormToContactProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/processes/ConvertFormToContactProcess.java @@ -1,8 +1,30 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Process to convert a form submission into a CRM contact. Handles duplicate ** detection by email, creates the contact if needed, updates the form ** submission record, and logs a Note activity on the contact. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.processes; @@ -21,7 +43,6 @@ import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; @@ -33,6 +54,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput; import com.kingsrook.qqq.backend.core.model.data.QRecord; +import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; @@ -51,7 +73,7 @@ import com.kingsrook.qqq.backend.core.utils.StringUtils; *******************************************************************************/ public class ConvertFormToContactProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "convertFormToContact"; + public static final String NAME = "crm_convert_form_to_contact"; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/processes/DetectDuplicatesProcess.java b/src/main/java/com/kingsrook/qbits/crm/core/processes/DetectDuplicatesProcess.java index 21924f3..6d1d89e 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/processes/DetectDuplicatesProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/processes/DetectDuplicatesProcess.java @@ -1,7 +1,29 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Process to detect duplicate contacts (by email) or companies (by domain). ** Returns groups where count > 1. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.processes; @@ -36,7 +58,7 @@ import com.kingsrook.qqq.backend.core.utils.StringUtils; *******************************************************************************/ public class DetectDuplicatesProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "detectDuplicates"; + public static final String NAME = "crm_detect_duplicates"; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/processes/GdprAnonymizeContactProcess.java b/src/main/java/com/kingsrook/qbits/crm/core/processes/GdprAnonymizeContactProcess.java index 5d76378..b738a6e 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/processes/GdprAnonymizeContactProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/processes/GdprAnonymizeContactProcess.java @@ -1,35 +1,49 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** GDPR right-to-erasure process. Anonymizes PII on a contact, scrubs audit ** log entries, deletes attachments, unenrolls from sequences, creates a ** consent-withdrawn record, and logs the anonymization event. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.processes; import java.time.Instant; import java.util.List; -import com.kingsrook.qbits.crm.audit.model.AuditLog; -import com.kingsrook.qbits.crm.core.model.Attachment; import com.kingsrook.qbits.crm.core.model.ConsentRecord; import com.kingsrook.qbits.crm.core.model.Contact; -import com.kingsrook.qbits.crm.core.model.enums.CrmAuditAction; import com.kingsrook.qbits.crm.core.model.enums.CrmConsentStatus; import com.kingsrook.qbits.crm.core.model.enums.CrmConsentType; import com.kingsrook.qbits.crm.core.model.enums.CrmEnrollmentStatus; -import com.kingsrook.qbits.crm.core.model.enums.CrmEntityType; -import com.kingsrook.qbits.crm.CrmSessionUtils; import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; -import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction; import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; -import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput; -import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; @@ -56,7 +70,7 @@ public class GdprAnonymizeContactProcess implements BackendStep, MetaDataProduce { private static final QLogger LOG = QLogger.getLogger(GdprAnonymizeContactProcess.class); - public static final String NAME = "gdprAnonymizeContact"; + public static final String NAME = "crm_gdpr_anonymize_contact"; private static final String ANONYMIZED = "[ANONYMIZED]"; @@ -92,7 +106,6 @@ public class GdprAnonymizeContactProcess implements BackendStep, MetaDataProduce public void run(RunBackendStepInput input, RunBackendStepOutput output) throws QException { Integer contactId = input.getValueInteger("contactId"); - String sessionUserId = CrmSessionUtils.getCurrentUserId(); /////////////////////////////////////////// // Step 1: load and validate contact // @@ -130,22 +143,12 @@ public class GdprAnonymizeContactProcess implements BackendStep, MetaDataProduce new UpdateInput(Contact.TABLE_NAME).withRecord(updateRecord)); /////////////////////////////////////////// - // Step 3: scrub audit log entries // - /////////////////////////////////////////// - scrubAuditLogEntries(contactId); - - /////////////////////////////////////////// - // Step 4: delete attachments // - /////////////////////////////////////////// - deleteAttachments(contactId); - - /////////////////////////////////////////// - // Step 5: unenroll from sequences // + // Step 3: unenroll from sequences // /////////////////////////////////////////// unenrollFromSequences(contactId); /////////////////////////////////////////// - // Step 6: create consent record // + // Step 4: create consent record // /////////////////////////////////////////// new InsertAction().execute( new InsertInput(ConsentRecord.TABLE_NAME).withRecordEntity( @@ -156,86 +159,12 @@ public class GdprAnonymizeContactProcess implements BackendStep, MetaDataProduce .withSource("GDPR Anonymization Process") .withConsentDate(Instant.now()))); - /////////////////////////////////////////// - // Step 7: log ANONYMIZED audit entry // - /////////////////////////////////////////// - new InsertAction().execute( - new InsertInput(AuditLog.TABLE_NAME).withRecordEntity( - new AuditLog() - .withEntityType(CrmEntityType.CONTACT.getPossibleValueId()) - .withEntityId(contactId) - .withAction(CrmAuditAction.ANONYMIZED.getPossibleValueId()) - .withUserId(sessionUserId) - .withMessage("Contact anonymized per GDPR right-to-erasure request"))); - output.addValue("contactId", contactId); output.addValue("anonymized", true); } - /*************************************************************************** - ** Scrub audit log entries for this contact. Sets a GDPR bypass flag on - ** the session so the immutability customizers allow the update. - ***************************************************************************/ - private void scrubAuditLogEntries(Integer contactId) throws QException - { - /////////////////////////////////////////// - // set GDPR bypass flag on session // - /////////////////////////////////////////// - QContext.getQSession().setValue("gdprBypass", "true"); - try - { - ///////////////////////////////////////////// - // query audit entries for this contact // - ///////////////////////////////////////////// - QueryOutput auditEntries = new QueryAction().execute( - new QueryInput(AuditLog.TABLE_NAME) - .withFilter(new QQueryFilter() - .withCriteria(new QFilterCriteria("entityType", QCriteriaOperator.EQUALS, CrmEntityType.CONTACT.getPossibleValueId())) - .withCriteria(new QFilterCriteria("entityId", QCriteriaOperator.EQUALS, contactId)))); - - ///////////////////////////////////////////// - // anonymize each entry // - ///////////////////////////////////////////// - for(QRecord record : auditEntries.getRecords()) - { - QRecord update = new QRecord(); - update.setValue("id", record.getValueInteger("id")); - update.setValue("oldValue", ANONYMIZED); - update.setValue("newValue", ANONYMIZED); - update.setValue("message", ANONYMIZED); - new UpdateAction().execute(new UpdateInput(AuditLog.TABLE_NAME).withRecords(List.of(update))); - } - } - finally - { - QContext.getQSession().setValue("gdprBypass", "false"); - } - } - - - - /*************************************************************************** - ** Delete attachments linked to this contact. - ***************************************************************************/ - private void deleteAttachments(Integer contactId) throws QException - { - QueryOutput attachments = new QueryAction().execute( - new QueryInput(Attachment.TABLE_NAME) - .withFilter(new QQueryFilter() - .withCriteria(new QFilterCriteria("entityType", QCriteriaOperator.EQUALS, CrmEntityType.CONTACT.getPossibleValueId())) - .withCriteria(new QFilterCriteria("entityId", QCriteriaOperator.EQUALS, contactId)))); - - for(QRecord record : attachments.getRecords()) - { - new DeleteAction().execute( - new DeleteInput(Attachment.TABLE_NAME).withPrimaryKeys(List.of(record.getValueInteger("id")))); - } - } - - - /*************************************************************************** ** Unenroll from any active sequence enrollments for this contact. ***************************************************************************/ @@ -244,7 +173,7 @@ public class GdprAnonymizeContactProcess implements BackendStep, MetaDataProduce try { QueryOutput enrollments = new QueryAction().execute( - new QueryInput("crmSequenceEnrollment") + new QueryInput("crm_sequence_enrollment") .withFilter(new QQueryFilter() .withCriteria(new QFilterCriteria("contactId", QCriteriaOperator.EQUALS, contactId)) .withCriteria(new QFilterCriteria("status", QCriteriaOperator.EQUALS, CrmEnrollmentStatus.ACTIVE.getPossibleValueId())))); @@ -256,7 +185,7 @@ public class GdprAnonymizeContactProcess implements BackendStep, MetaDataProduce .withValue("status", CrmEnrollmentStatus.UNENROLLED.getPossibleValueId()); new UpdateAction().execute( - new UpdateInput("crmSequenceEnrollment").withRecord(updateRecord)); + new UpdateInput("crm_sequence_enrollment").withRecord(updateRecord)); } } catch(Exception e) diff --git a/src/main/java/com/kingsrook/qbits/crm/core/processes/ImportContactsProcess.java b/src/main/java/com/kingsrook/qbits/crm/core/processes/ImportContactsProcess.java index dea27e6..7ca32c0 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/processes/ImportContactsProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/processes/ImportContactsProcess.java @@ -1,19 +1,37 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Simplified import process for contacts. Takes a list of QRecords, ** validates required fields, checks for duplicates by email, inserts new - ** contacts, and logs audit entries. + ** contacts, with core table auditing. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.processes; -import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; -import com.kingsrook.qbits.crm.audit.model.AuditLog; import com.kingsrook.qbits.crm.core.model.Contact; -import com.kingsrook.qbits.crm.core.model.enums.CrmAuditAction; -import com.kingsrook.qbits.crm.core.model.enums.CrmEntityType; import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; @@ -22,10 +40,6 @@ import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; import com.kingsrook.qqq.backend.core.model.data.QRecord; @@ -43,7 +57,7 @@ import com.kingsrook.qqq.backend.core.utils.StringUtils; *******************************************************************************/ public class ImportContactsProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "importContacts"; + public static final String NAME = "crm_import_contacts"; @@ -129,24 +143,11 @@ public class ImportContactsProcess implements BackendStep, MetaDataProducerInter .withValue("phone", inputRecord.getValueString("phone")) .withValue("ownerUserId", sessionUserId); - InsertOutput insertOutput = new InsertAction().execute( + new InsertAction().execute( new InsertInput(Contact.TABLE_NAME).withRecord(newContact)); - Integer newContactId = insertOutput.getRecords().get(0).getValueInteger("id"); existingEmails.add(email.toLowerCase()); - /////////////////////////////////////////// - // log IMPORTED audit entry // - /////////////////////////////////////////// - new InsertAction().execute( - new InsertInput(AuditLog.TABLE_NAME).withRecordEntity( - new AuditLog() - .withEntityType(CrmEntityType.CONTACT.getPossibleValueId()) - .withEntityId(newContactId) - .withAction(CrmAuditAction.IMPORTED.getPossibleValueId()) - .withUserId(sessionUserId) - .withMessage("Contact imported"))); - importedCount++; } diff --git a/src/main/java/com/kingsrook/qbits/crm/core/processes/MergeCompaniesProcess.java b/src/main/java/com/kingsrook/qbits/crm/core/processes/MergeCompaniesProcess.java index a2f958b..b8977ea 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/processes/MergeCompaniesProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/processes/MergeCompaniesProcess.java @@ -1,34 +1,48 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Process to merge two companies. Re-links contacts, deals, activities, and - ** tags from the secondary to the primary, then deletes the secondary company - ** and logs audit entries. + ** related records from the secondary to the primary, then deletes the secondary company + ** with core table auditing. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.processes; -import java.util.HashSet; import java.util.List; -import java.util.Set; -import com.kingsrook.qbits.crm.activities.model.Activity; -import com.kingsrook.qbits.crm.audit.model.AuditLog; -import com.kingsrook.qbits.crm.core.model.Company; -import com.kingsrook.qbits.crm.core.model.CompanyTag; -import com.kingsrook.qbits.crm.core.model.Contact; -import com.kingsrook.qbits.crm.core.model.enums.CrmAuditAction; -import com.kingsrook.qbits.crm.core.model.enums.CrmEntityType; -import com.kingsrook.qbits.crm.deals.model.Deal; import com.kingsrook.qbits.crm.CrmSessionUtils; +import com.kingsrook.qbits.crm.activities.model.Activity; +import com.kingsrook.qbits.crm.core.model.Company; +import com.kingsrook.qbits.crm.core.model.Contact; +import com.kingsrook.qbits.crm.deals.model.Deal; import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction; import com.kingsrook.qqq.backend.core.actions.tables.GetAction; -import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; @@ -52,7 +66,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; *******************************************************************************/ public class MergeCompaniesProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "mergeCompanies"; + public static final String NAME = "crm_merge_companies"; @@ -117,10 +131,6 @@ public class MergeCompaniesProcess implements BackendStep, MetaDataProducerInter /////////////////////////////////////////////// relinkRecords(Activity.TABLE_NAME, "companyId", secondaryCompanyId, primaryCompanyId); - /////////////////////////////////////////////// - // Re-link CompanyTag rows (skip duplicates) // - /////////////////////////////////////////////// - relinkCompanyTags(primaryCompanyId, secondaryCompanyId); /////////////////////////////////////////////// // Delete the secondary company // @@ -128,27 +138,6 @@ public class MergeCompaniesProcess implements BackendStep, MetaDataProducerInter new DeleteAction().execute( new DeleteInput(Company.TABLE_NAME).withPrimaryKeys(List.of(secondaryCompanyId))); - /////////////////////////////////////////////// - // Log audit entries // - /////////////////////////////////////////////// - new InsertAction().execute( - new InsertInput(AuditLog.TABLE_NAME).withRecordEntity( - new AuditLog() - .withEntityType(CrmEntityType.COMPANY.getPossibleValueId()) - .withEntityId(primaryCompanyId) - .withAction(CrmAuditAction.MERGED.getPossibleValueId()) - .withUserId(sessionUserId) - .withMessage("Merged company " + secondaryCompanyId + " into this company"))); - - new InsertAction().execute( - new InsertInput(AuditLog.TABLE_NAME).withRecordEntity( - new AuditLog() - .withEntityType(CrmEntityType.COMPANY.getPossibleValueId()) - .withEntityId(secondaryCompanyId) - .withAction(CrmAuditAction.DELETED.getPossibleValueId()) - .withUserId(sessionUserId) - .withMessage("Company deleted during merge into company " + primaryCompanyId))); - output.addValue("primaryCompanyId", primaryCompanyId); } @@ -177,44 +166,4 @@ public class MergeCompaniesProcess implements BackendStep, MetaDataProducerInter - /*************************************************************************** - ** Re-link CompanyTag rows: skip duplicates (same tagId already on primary). - ***************************************************************************/ - private void relinkCompanyTags(Integer primaryCompanyId, Integer secondaryCompanyId) throws QException - { - QueryOutput primaryTags = new QueryAction().execute( - new QueryInput(CompanyTag.TABLE_NAME) - .withFilter(new QQueryFilter() - .withCriteria(new QFilterCriteria("companyId", QCriteriaOperator.EQUALS, primaryCompanyId)))); - - Set primaryTagIds = new HashSet<>(); - for(QRecord record : primaryTags.getRecords()) - { - primaryTagIds.add(record.getValueInteger("tagId")); - } - - QueryOutput secondaryTags = new QueryAction().execute( - new QueryInput(CompanyTag.TABLE_NAME) - .withFilter(new QQueryFilter() - .withCriteria(new QFilterCriteria("companyId", QCriteriaOperator.EQUALS, secondaryCompanyId)))); - - for(QRecord record : secondaryTags.getRecords()) - { - Integer tagId = record.getValueInteger("tagId"); - if(primaryTagIds.contains(tagId)) - { - new DeleteAction().execute( - new DeleteInput(CompanyTag.TABLE_NAME).withPrimaryKeys(List.of(record.getValueInteger("id")))); - } - else - { - QRecord updateRecord = new QRecord() - .withValue("id", record.getValueInteger("id")) - .withValue("companyId", primaryCompanyId); - new UpdateAction().execute( - new UpdateInput(CompanyTag.TABLE_NAME).withRecord(updateRecord)); - } - } - } - } diff --git a/src/main/java/com/kingsrook/qbits/crm/core/processes/MergeContactsProcess.java b/src/main/java/com/kingsrook/qbits/crm/core/processes/MergeContactsProcess.java index f245a29..1384dc2 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/processes/MergeContactsProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/processes/MergeContactsProcess.java @@ -1,34 +1,50 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* - ** Process to merge two contacts. Re-links activities, deal contacts, tags, + ** Process to merge two contacts. Re-links activities, deal contacts, ** and email list memberships from the secondary to the primary, then deletes - ** the secondary contact and logs audit entries. + ** the secondary contact with core table auditing. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.processes; import java.util.HashSet; import java.util.List; import java.util.Set; -import com.kingsrook.qbits.crm.activities.model.Activity; -import com.kingsrook.qbits.crm.audit.model.AuditLog; -import com.kingsrook.qbits.crm.core.model.Contact; -import com.kingsrook.qbits.crm.core.model.ContactTag; -import com.kingsrook.qbits.crm.core.model.EmailListMember; -import com.kingsrook.qbits.crm.core.model.enums.CrmAuditAction; -import com.kingsrook.qbits.crm.core.model.enums.CrmEntityType; -import com.kingsrook.qbits.crm.deals.model.DealContact; import com.kingsrook.qbits.crm.CrmSessionUtils; +import com.kingsrook.qbits.crm.activities.model.Activity; +import com.kingsrook.qbits.crm.core.model.Contact; +import com.kingsrook.qbits.crm.core.model.EmailListMember; +import com.kingsrook.qbits.crm.deals.model.DealContact; import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction; import com.kingsrook.qqq.backend.core.actions.tables.GetAction; -import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; @@ -52,7 +68,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; *******************************************************************************/ public class MergeContactsProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "mergeContacts"; + public static final String NAME = "crm_merge_contacts"; @@ -115,10 +131,6 @@ public class MergeContactsProcess implements BackendStep, MetaDataProducerInterf /////////////////////////////////////////////// relinkDealContacts(primaryContactId, secondaryContactId); - /////////////////////////////////////////////// - // Re-link ContactTag rows // - /////////////////////////////////////////////// - relinkJunctionRecords(ContactTag.TABLE_NAME, "contactId", "tagId", primaryContactId, secondaryContactId); /////////////////////////////////////////////// // Re-link EmailListMember rows // @@ -131,27 +143,6 @@ public class MergeContactsProcess implements BackendStep, MetaDataProducerInterf new DeleteAction().execute( new DeleteInput(Contact.TABLE_NAME).withPrimaryKeys(List.of(secondaryContactId))); - /////////////////////////////////////////////// - // Log audit entries // - /////////////////////////////////////////////// - new InsertAction().execute( - new InsertInput(AuditLog.TABLE_NAME).withRecordEntity( - new AuditLog() - .withEntityType(CrmEntityType.CONTACT.getPossibleValueId()) - .withEntityId(primaryContactId) - .withAction(CrmAuditAction.MERGED.getPossibleValueId()) - .withUserId(sessionUserId) - .withMessage("Merged contact " + secondaryContactId + " into this contact"))); - - new InsertAction().execute( - new InsertInput(AuditLog.TABLE_NAME).withRecordEntity( - new AuditLog() - .withEntityType(CrmEntityType.CONTACT.getPossibleValueId()) - .withEntityId(secondaryContactId) - .withAction(CrmAuditAction.DELETED.getPossibleValueId()) - .withUserId(sessionUserId) - .withMessage("Contact deleted during merge into contact " + primaryContactId))); - output.addValue("primaryContactId", primaryContactId); } diff --git a/src/main/java/com/kingsrook/qbits/crm/core/processes/SubscribeToListProcess.java b/src/main/java/com/kingsrook/qbits/crm/core/processes/SubscribeToListProcess.java index 9013ef4..fe721da 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/processes/SubscribeToListProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/processes/SubscribeToListProcess.java @@ -1,7 +1,29 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Process to subscribe an email address to an email list. Handles ** resubscription after unsubscribe and links to an existing contact. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.processes; @@ -15,7 +37,6 @@ import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; @@ -26,6 +47,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput; import com.kingsrook.qqq.backend.core.model.data.QRecord; +import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; @@ -44,7 +66,7 @@ import com.kingsrook.qqq.backend.core.utils.StringUtils; *******************************************************************************/ public class SubscribeToListProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "subscribeToList"; + public static final String NAME = "crm_subscribe_to_list"; diff --git a/src/main/java/com/kingsrook/qbits/crm/core/processes/UnsubscribeFromListProcess.java b/src/main/java/com/kingsrook/qbits/crm/core/processes/UnsubscribeFromListProcess.java index a8ed854..86e2237 100644 --- a/src/main/java/com/kingsrook/qbits/crm/core/processes/UnsubscribeFromListProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/core/processes/UnsubscribeFromListProcess.java @@ -1,7 +1,29 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Process to unsubscribe an email address from an email list. Sets the member ** status to UNSUBSCRIBED and records the unsubscribedDate. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.processes; @@ -13,7 +35,6 @@ import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; @@ -23,6 +44,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput; import com.kingsrook.qqq.backend.core.model.data.QRecord; +import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; @@ -40,7 +62,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; *******************************************************************************/ public class UnsubscribeFromListProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "unsubscribeFromList"; + public static final String NAME = "crm_unsubscribe_from_list"; diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/customizers/DealInitializationCustomizer.java b/src/main/java/com/kingsrook/qbits/crm/deals/customizers/DealInitializationCustomizer.java index 92d94a3..f92b27c 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/customizers/DealInitializationCustomizer.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/customizers/DealInitializationCustomizer.java @@ -1,8 +1,30 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** POST_INSERT table customizer that initializes newly-created deals with ** computed fields: stageEnteredDate, weightedAmount, amountInBaseCurrency, ** and the initial DealStageHistory row. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.customizers; @@ -10,11 +32,11 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.time.Instant; import java.util.List; +import com.kingsrook.qbits.crm.CrmSessionUtils; import com.kingsrook.qbits.crm.deals.model.Deal; -import com.kingsrook.qbits.crm.sync.CrmCurrencyUtils; import com.kingsrook.qbits.crm.deals.model.DealStageHistory; import com.kingsrook.qbits.crm.deals.model.PipelineStage; -import com.kingsrook.qbits.crm.CrmSessionUtils; +import com.kingsrook.qbits.crm.sync.CrmCurrencyUtils; import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPostInsertCustomizer; import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/customizers/DealProductRecalculationCustomizer.java b/src/main/java/com/kingsrook/qbits/crm/deals/customizers/DealProductRecalculationCustomizer.java index c4ba7d3..204f768 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/customizers/DealProductRecalculationCustomizer.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/customizers/DealProductRecalculationCustomizer.java @@ -1,8 +1,30 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** POST_INSERT, POST_UPDATE, and POST_DELETE table customizer for ** DealProduct that recalculates line-item totalAmount and rolls up ** the sum to the parent Deal's amount field. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.customizers; diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/customizers/DealStageChangeCustomizer.java b/src/main/java/com/kingsrook/qbits/crm/deals/customizers/DealStageChangeCustomizer.java index 59ca773..12df780 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/customizers/DealStageChangeCustomizer.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/customizers/DealStageChangeCustomizer.java @@ -1,3 +1,24 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** PRE_UPDATE table customizer that handles deal pipeline stage transitions. ** @@ -9,6 +30,7 @@ ** - clears actualCloseDate and winLossReasonId on reopen ** - inserts a DealStageHistory row *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.customizers; @@ -21,11 +43,11 @@ import java.time.LocalDate; import java.util.List; import java.util.Map; import java.util.Objects; +import com.kingsrook.qbits.crm.CrmSessionUtils; import com.kingsrook.qbits.crm.deals.model.Deal; -import com.kingsrook.qbits.crm.sync.CrmCurrencyUtils; import com.kingsrook.qbits.crm.deals.model.DealStageHistory; import com.kingsrook.qbits.crm.deals.model.PipelineStage; -import com.kingsrook.qbits.crm.CrmSessionUtils; +import com.kingsrook.qbits.crm.sync.CrmCurrencyUtils; import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPreUpdateCustomizer; import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/model/ContactRole.java b/src/main/java/com/kingsrook/qbits/crm/deals/model/ContactRole.java index 371c28c..2a53645 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/model/ContactRole.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/model/ContactRole.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for ContactRole table *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.model; @@ -30,7 +52,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; ) public class ContactRole extends QRecordEntity { - public static final String TABLE_NAME = "crmContactRole"; + public static final String TABLE_NAME = "crm_contact_role"; diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/model/Deal.java b/src/main/java/com/kingsrook/qbits/crm/deals/model/Deal.java index 62df13b..d087690 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/model/Deal.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/model/Deal.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for Deal table *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.model; @@ -41,7 +63,7 @@ import com.kingsrook.qqq.backend.core.utils.collections.MutableList; /******************************************************************************* ** QRecord Entity for Deal table -- the primary revenue-tracking record in the ** CRM. Deals move through pipeline stages and are linked to contacts, companies, - ** products, activities, and tags. + ** products and activities. *******************************************************************************/ @QMetaDataProducingEntity( produceTableMetaData = true, @@ -58,11 +80,6 @@ import com.kingsrook.qqq.backend.core.utils.collections.MutableList; joinFieldName = "dealId", childJoin = @ChildJoin(enabled = true), childRecordListWidget = @ChildRecordListWidget(label = "Products", enabled = true, maxRows = 50)), - @ChildTable( - childTableEntityClass = DealTag.class, - joinFieldName = "dealId", - childJoin = @ChildJoin(enabled = true), - childRecordListWidget = @ChildRecordListWidget(label = "Tags", enabled = true, maxRows = 50)), @ChildTable( childTableEntityClass = DealStageHistory.class, joinFieldName = "dealId", @@ -77,7 +94,7 @@ import com.kingsrook.qqq.backend.core.utils.collections.MutableList; ) public class Deal extends QRecordEntity { - public static final String TABLE_NAME = "crmDeal"; + public static final String TABLE_NAME = "crm_deal"; diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/model/DealContact.java b/src/main/java/com/kingsrook/qbits/crm/deals/model/DealContact.java index 35dbfe8..f28bb75 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/model/DealContact.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/model/DealContact.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for DealContact table *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.model; @@ -29,7 +51,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; ) public class DealContact extends QRecordEntity { - public static final String TABLE_NAME = "crmDealContact"; + public static final String TABLE_NAME = "crm_deal_contact"; diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/model/DealProduct.java b/src/main/java/com/kingsrook/qbits/crm/deals/model/DealProduct.java index 4a2f8c6..3eec63e 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/model/DealProduct.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/model/DealProduct.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for the crm_deal_product table. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.model; @@ -32,7 +54,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.Tier; ) public class DealProduct extends QRecordEntity { - public static final String TABLE_NAME = "crmDealProduct"; + public static final String TABLE_NAME = "crm_deal_product"; diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/model/DealStageHistory.java b/src/main/java/com/kingsrook/qbits/crm/deals/model/DealStageHistory.java index 4d56e13..82de0db 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/model/DealStageHistory.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/model/DealStageHistory.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for DealStageHistory table *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.model; @@ -27,7 +49,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.SectionFactory; ) public class DealStageHistory extends QRecordEntity { - public static final String TABLE_NAME = "crmDealStageHistory"; + public static final String TABLE_NAME = "crm_deal_stage_history"; diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/model/DealTag.java b/src/main/java/com/kingsrook/qbits/crm/deals/model/DealTag.java deleted file mode 100644 index 3dd7e4c..0000000 --- a/src/main/java/com/kingsrook/qbits/crm/deals/model/DealTag.java +++ /dev/null @@ -1,217 +0,0 @@ -/******************************************************************************* - ** QRecord Entity for DealTag table - *******************************************************************************/ -package com.kingsrook.qbits.crm.deals.model; - - -import java.time.Instant; -import com.kingsrook.qbits.crm.core.model.Tag; -import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.model.data.QField; -import com.kingsrook.qqq.backend.core.model.data.QRecord; -import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; -import com.kingsrook.qqq.backend.core.model.metadata.QInstance; -import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon; -import com.kingsrook.qqq.backend.core.model.metadata.producers.MetaDataCustomizerInterface; -import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.QMetaDataProducingEntity; -import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.tables.SectionFactory; -import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; - - -/******************************************************************************* - ** QRecord Entity for DealTag junction table -- many-to-many link between - ** deals and tags. - *******************************************************************************/ -@QMetaDataProducingEntity( - produceTableMetaData = true, - tableMetaDataCustomizer = DealTag.TableMetaDataCustomizer.class -) -public class DealTag extends QRecordEntity -{ - public static final String TABLE_NAME = "crmDealTag"; - - - - /*************************************************************************** - ** - ***************************************************************************/ - public static class TableMetaDataCustomizer implements MetaDataCustomizerInterface - { - - /*************************************************************************** - ** - ***************************************************************************/ - @Override - public QTableMetaData customizeMetaData(QInstance qInstance, QTableMetaData table) throws QException - { - table - .withIcon(new QIcon().withName("label")) - .withRecordLabelFormat("Deal %s - Tag %s") - .withRecordLabelFields("dealId", "tagId") - .withUniqueKey(new UniqueKey("dealId", "tagId")) - .withSection(SectionFactory.defaultT1("id", "dealId", "tagId")) - .withSection(SectionFactory.defaultT3("createDate")); - - return (table); - } - } - - - - @QField(isEditable = false, isPrimaryKey = true) - private Integer id; - - @QField(isRequired = true, possibleValueSourceName = Deal.TABLE_NAME) - private Integer dealId; - - @QField(isRequired = true, possibleValueSourceName = Tag.TABLE_NAME) - private Integer tagId; - - @QField(isEditable = false) - private Instant createDate; - - - - /******************************************************************************* - ** Default constructor - *******************************************************************************/ - public DealTag() - { - } - - - - /******************************************************************************* - ** Constructor that takes a QRecord - *******************************************************************************/ - public DealTag(QRecord record) - { - populateFromQRecord(record); - } - - - - /******************************************************************************* - ** Getter for id - *******************************************************************************/ - public Integer getId() - { - return (this.id); - } - - - - /******************************************************************************* - ** Setter for id - *******************************************************************************/ - public void setId(Integer id) - { - this.id = id; - } - - - - /******************************************************************************* - ** Fluent setter for id - *******************************************************************************/ - public DealTag withId(Integer id) - { - this.id = id; - return (this); - } - - - - /******************************************************************************* - ** Getter for dealId - *******************************************************************************/ - public Integer getDealId() - { - return (this.dealId); - } - - - - /******************************************************************************* - ** Setter for dealId - *******************************************************************************/ - public void setDealId(Integer dealId) - { - this.dealId = dealId; - } - - - - /******************************************************************************* - ** Fluent setter for dealId - *******************************************************************************/ - public DealTag withDealId(Integer dealId) - { - this.dealId = dealId; - return (this); - } - - - - /******************************************************************************* - ** Getter for tagId - *******************************************************************************/ - public Integer getTagId() - { - return (this.tagId); - } - - - - /******************************************************************************* - ** Setter for tagId - *******************************************************************************/ - public void setTagId(Integer tagId) - { - this.tagId = tagId; - } - - - - /******************************************************************************* - ** Fluent setter for tagId - *******************************************************************************/ - public DealTag withTagId(Integer tagId) - { - this.tagId = tagId; - return (this); - } - - - - /******************************************************************************* - ** Getter for createDate - *******************************************************************************/ - public Instant getCreateDate() - { - return (this.createDate); - } - - - - /******************************************************************************* - ** Setter for createDate - *******************************************************************************/ - public void setCreateDate(Instant createDate) - { - this.createDate = createDate; - } - - - - /******************************************************************************* - ** Fluent setter for createDate - *******************************************************************************/ - public DealTag withCreateDate(Instant createDate) - { - this.createDate = createDate; - return (this); - } - -} diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/model/Pipeline.java b/src/main/java/com/kingsrook/qbits/crm/deals/model/Pipeline.java index 859fb49..d0a5d0b 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/model/Pipeline.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/model/Pipeline.java @@ -1,11 +1,32 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for Pipeline table *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.model; import java.time.Instant; -import java.util.List; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.data.QField; import com.kingsrook.qqq.backend.core.model.data.QRecord; @@ -41,7 +62,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; ) public class Pipeline extends QRecordEntity { - public static final String TABLE_NAME = "crmPipeline"; + public static final String TABLE_NAME = "crm_pipeline"; diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/model/PipelineStage.java b/src/main/java/com/kingsrook/qbits/crm/deals/model/PipelineStage.java index 37cc4e2..77baab2 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/model/PipelineStage.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/model/PipelineStage.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for PipelineStage table *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.model; @@ -41,7 +63,7 @@ import com.kingsrook.qqq.backend.core.model.statusmessages.BadInputStatusMessage ) public class PipelineStage extends QRecordEntity { - public static final String TABLE_NAME = "crmPipelineStage"; + public static final String TABLE_NAME = "crm_pipeline_stage"; diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/model/Product.java b/src/main/java/com/kingsrook/qbits/crm/deals/model/Product.java index 140703f..88a002f 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/model/Product.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/model/Product.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for the crm_product table. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.model; @@ -44,7 +66,7 @@ import com.kingsrook.qqq.backend.core.model.statusmessages.BadInputStatusMessage ) public class Product extends QRecordEntity { - public static final String TABLE_NAME = "crmProduct"; + public static final String TABLE_NAME = "crm_product"; diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/model/WinLossReason.java b/src/main/java/com/kingsrook/qbits/crm/deals/model/WinLossReason.java index 43c8940..cd0dccb 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/model/WinLossReason.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/model/WinLossReason.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for WinLossReason table *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.model; @@ -31,7 +53,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; ) public class WinLossReason extends QRecordEntity { - public static final String TABLE_NAME = "crmWinLossReason"; + public static final String TABLE_NAME = "crm_win_loss_reason"; diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/processes/CloneDealProcess.java b/src/main/java/com/kingsrook/qbits/crm/deals/processes/CloneDealProcess.java index 845fae0..b3bebdd 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/processes/CloneDealProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/processes/CloneDealProcess.java @@ -1,8 +1,30 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* - ** Process to clone a deal including its contacts, products, and tags. + ** Process to clone a deal including its contacts and products. ** The cloned deal gets a "(Copy)" suffix, resets to the first pipeline stage, ** and clears close-related fields. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.processes; @@ -11,7 +33,6 @@ import java.util.List; import com.kingsrook.qbits.crm.deals.model.Deal; import com.kingsrook.qbits.crm.deals.model.DealContact; import com.kingsrook.qbits.crm.deals.model.DealProduct; -import com.kingsrook.qbits.crm.deals.model.DealTag; import com.kingsrook.qbits.crm.deals.model.PipelineStage; import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; import com.kingsrook.qqq.backend.core.actions.tables.GetAction; @@ -45,7 +66,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; *******************************************************************************/ public class CloneDealProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "cloneDeal"; + public static final String NAME = "crm_clone_deal"; @@ -127,10 +148,6 @@ public class CloneDealProcess implements BackendStep, MetaDataProducerInterface< ///////////////////////////////////////////// cloneChildRecords(DealProduct.TABLE_NAME, "dealId", dealId, newDealId); - ///////////////////////////////////////////// - // Step 6: clone DealTag rows // - ///////////////////////////////////////////// - cloneChildRecords(DealTag.TABLE_NAME, "dealId", dealId, newDealId); output.addValue("dealId", newDealId); } diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/processes/ConvertLeadProcess.java b/src/main/java/com/kingsrook/qbits/crm/deals/processes/ConvertLeadProcess.java index b4443a5..e4026ec 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/processes/ConvertLeadProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/processes/ConvertLeadProcess.java @@ -1,19 +1,38 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Process to convert a contact (lead) into a deal opportunity. Updates the ** contact's lifecycle stage to "Opportunity", creates a new Deal, links - ** them via DealContact junction, and logs audit entries. + ** them via DealContact junction, with core table auditing. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.processes; import java.math.BigDecimal; import java.time.Instant; import java.util.List; -import com.kingsrook.qbits.crm.audit.model.AuditLog; import com.kingsrook.qbits.crm.core.model.Contact; import com.kingsrook.qbits.crm.core.model.LifecycleStage; -import com.kingsrook.qbits.crm.core.model.enums.CrmAuditAction; -import com.kingsrook.qbits.crm.core.model.enums.CrmEntityType; import com.kingsrook.qbits.crm.deals.model.Deal; import com.kingsrook.qbits.crm.deals.model.DealContact; import com.kingsrook.qbits.crm.deals.model.Pipeline; @@ -57,7 +76,7 @@ import com.kingsrook.qqq.backend.core.utils.ValueUtils; *******************************************************************************/ public class ConvertLeadProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "convertLead"; + public static final String NAME = "crm_convert_lead"; @@ -174,29 +193,6 @@ public class ConvertLeadProcess implements BackendStep, MetaDataProducerInterfac new InsertAction().execute( new InsertInput(DealContact.TABLE_NAME).withRecordEntity(dealContact)); - ///////////////////////////////////////////////////////////////////// - // Step 7: log audit entries // - ///////////////////////////////////////////////////////////////////// - AuditLog contactAudit = new AuditLog() - .withEntityType(CrmEntityType.CONTACT.getPossibleValueId()) - .withEntityId(contactId) - .withAction(CrmAuditAction.STAGE_CHANGED.getPossibleValueId()) - .withUserId(userId) - .withFieldName("lifecycleStageId") - .withNewValue(opportunityStageId != null ? String.valueOf(opportunityStageId) : null) - .withMessage("Lead converted to deal: " + dealName); - - AuditLog dealAudit = new AuditLog() - .withEntityType(CrmEntityType.DEAL.getPossibleValueId()) - .withEntityId(dealId) - .withAction(CrmAuditAction.CREATED.getPossibleValueId()) - .withUserId(userId) - .withMessage("Deal created from lead conversion (contact " + contactId + ")"); - - new InsertAction().execute( - new InsertInput(AuditLog.TABLE_NAME).withRecords(List.of( - contactAudit.toQRecord(), dealAudit.toQRecord()))); - output.addValue("dealId", dealId); } diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/processes/ManageContactOnDealProcess.java b/src/main/java/com/kingsrook/qbits/crm/deals/processes/ManageContactOnDealProcess.java index ec1ef8d..5ce2cf8 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/processes/ManageContactOnDealProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/processes/ManageContactOnDealProcess.java @@ -1,8 +1,30 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Process to add or remove a contact from a deal via the DealContact ** junction table. Supports isPrimary enforcement (clearing other primaries ** when a new primary is set) and optional contactRoleId assignment. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.processes; @@ -45,7 +67,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; *******************************************************************************/ public class ManageContactOnDealProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "manageContactOnDeal"; + public static final String NAME = "crm_manage_contact_on_deal"; diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/processes/MoveDealStageProcess.java b/src/main/java/com/kingsrook/qbits/crm/deals/processes/MoveDealStageProcess.java index 4411de2..136f205 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/processes/MoveDealStageProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/processes/MoveDealStageProcess.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Process to move a deal from its current pipeline stage to a target stage. ** Validates stage membership in the pipeline, checks required fields, updates ** weighted amount, sets close date on terminal stages, and logs stage history - ** and audit entries. + ** and core table auditing. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.processes; @@ -13,9 +35,6 @@ import java.time.Instant; import java.time.LocalDate; import java.time.temporal.ChronoUnit; import java.util.List; -import com.kingsrook.qbits.crm.audit.model.AuditLog; -import com.kingsrook.qbits.crm.core.model.enums.CrmAuditAction; -import com.kingsrook.qbits.crm.core.model.enums.CrmEntityType; import com.kingsrook.qbits.crm.deals.model.Deal; import com.kingsrook.qbits.crm.deals.model.DealStageHistory; import com.kingsrook.qbits.crm.deals.model.PipelineStage; @@ -52,7 +71,7 @@ import com.kingsrook.qqq.backend.core.utils.StringUtils; *******************************************************************************/ public class MoveDealStageProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "moveDealStage"; + public static final String NAME = "crm_move_deal_stage"; @@ -196,22 +215,6 @@ public class MoveDealStageProcess implements BackendStep, MetaDataProducerInterf new InsertAction().execute( new InsertInput(DealStageHistory.TABLE_NAME).withRecordEntity(history)); - ////////////////////////////////////////////////////////////// - // Step 10: log audit entry // - ////////////////////////////////////////////////////////////// - AuditLog auditEntry = new AuditLog() - .withEntityType(CrmEntityType.DEAL.getPossibleValueId()) - .withEntityId(dealId) - .withAction(CrmAuditAction.STAGE_CHANGED.getPossibleValueId()) - .withUserId(sessionUserId) - .withFieldName("pipelineStageId") - .withOldValue(oldStageId != null ? String.valueOf(oldStageId) : null) - .withNewValue(String.valueOf(targetStageId)) - .withMessage("Deal moved to stage: " + targetStage.getName()); - - new InsertAction().execute( - new InsertInput(AuditLog.TABLE_NAME).withRecordEntity(auditEntry)); - output.addValue("dealId", dealId); output.addValue("newStageId", targetStageId); } diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/processes/ReopenDealProcess.java b/src/main/java/com/kingsrook/qbits/crm/deals/processes/ReopenDealProcess.java index afe1ca4..7e68c98 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/processes/ReopenDealProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/processes/ReopenDealProcess.java @@ -1,18 +1,37 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Process to reopen a closed deal by moving it to an active (non-closed) ** pipeline stage. Clears actualCloseDate and winLossReasonId, recalculates - ** weighted amount, and logs stage history and audit entries. + ** weighted amount, and logs stage history and core table auditing. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.processes; +import java.math.BigDecimal; import java.time.Instant; import java.time.temporal.ChronoUnit; -import java.math.BigDecimal; import java.util.List; -import com.kingsrook.qbits.crm.audit.model.AuditLog; -import com.kingsrook.qbits.crm.core.model.enums.CrmAuditAction; -import com.kingsrook.qbits.crm.core.model.enums.CrmEntityType; import com.kingsrook.qbits.crm.deals.model.Deal; import com.kingsrook.qbits.crm.deals.model.DealStageHistory; import com.kingsrook.qbits.crm.deals.model.PipelineStage; @@ -46,7 +65,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; *******************************************************************************/ public class ReopenDealProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "reopenDeal"; + public static final String NAME = "crm_reopen_deal"; @@ -174,22 +193,6 @@ public class ReopenDealProcess implements BackendStep, MetaDataProducerInterface new InsertAction().execute( new InsertInput(DealStageHistory.TABLE_NAME).withRecordEntity(history)); - ////////////////////////////////////////////////////////////// - // Step 9: log audit entry // - ////////////////////////////////////////////////////////////// - AuditLog auditEntry = new AuditLog() - .withEntityType(CrmEntityType.DEAL.getPossibleValueId()) - .withEntityId(dealId) - .withAction(CrmAuditAction.STAGE_CHANGED.getPossibleValueId()) - .withUserId(sessionUserId) - .withFieldName("pipelineStageId") - .withOldValue(oldStageId != null ? String.valueOf(oldStageId) : null) - .withNewValue(String.valueOf(targetStageId)) - .withMessage("Deal reopened to stage: " + targetStage.getName()); - - new InsertAction().execute( - new InsertInput(AuditLog.TABLE_NAME).withRecordEntity(auditEntry)); - output.addValue("dealId", dealId); output.addValue("newStageId", targetStageId); } diff --git a/src/main/java/com/kingsrook/qbits/crm/deals/processes/TransferOwnershipProcess.java b/src/main/java/com/kingsrook/qbits/crm/deals/processes/TransferOwnershipProcess.java index 1cd1a44..a1e4167 100644 --- a/src/main/java/com/kingsrook/qbits/crm/deals/processes/TransferOwnershipProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/deals/processes/TransferOwnershipProcess.java @@ -1,26 +1,44 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Process to transfer ownership of all contacts, companies, and deals from - ** one user to another, logging audit entries for each change. + ** one user to another, using core table auditing for each change. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.processes; import java.util.List; -import com.kingsrook.qbits.crm.audit.model.AuditLog; import com.kingsrook.qbits.crm.core.model.Company; import com.kingsrook.qbits.crm.core.model.Contact; -import com.kingsrook.qbits.crm.core.model.enums.CrmAuditAction; import com.kingsrook.qbits.crm.core.model.enums.CrmEntityType; import com.kingsrook.qbits.crm.deals.model.Deal; import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; -import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput; -import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; @@ -45,7 +63,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; *******************************************************************************/ public class TransferOwnershipProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "transferOwnership"; + public static final String NAME = "crm_transfer_ownership"; @@ -124,20 +142,7 @@ public class TransferOwnershipProcess implements BackendStep, MetaDataProducerIn new UpdateAction().execute( new UpdateInput(tableName).withRecord(updateRecord)); - ////////////////////////////////// - // log audit entry // - ////////////////////////////////// - new InsertAction().execute( - new InsertInput(AuditLog.TABLE_NAME).withRecordEntity( - new AuditLog() - .withEntityType(entityType.getPossibleValueId()) - .withEntityId(recordId) - .withAction(CrmAuditAction.OWNER_CHANGED.getPossibleValueId()) - .withUserId(sessionUserId) - .withFieldName("ownerUserId") - .withOldValue(fromUserId) - .withNewValue(toUserId) - .withMessage("Ownership transferred from " + fromUserId + " to " + toUserId))); + } } diff --git a/src/main/java/com/kingsrook/qbits/crm/email/customizers/EmailTemplatePreDeleteCustomizer.java b/src/main/java/com/kingsrook/qbits/crm/email/customizers/EmailTemplatePreDeleteCustomizer.java index e327665..eeafc4b 100644 --- a/src/main/java/com/kingsrook/qbits/crm/email/customizers/EmailTemplatePreDeleteCustomizer.java +++ b/src/main/java/com/kingsrook/qbits/crm/email/customizers/EmailTemplatePreDeleteCustomizer.java @@ -1,7 +1,29 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** PRE_DELETE customizer for EmailTemplate -- prevents deletion of templates ** referenced by active email sequences. *******************************************************************************/ + package com.kingsrook.qbits.crm.email.customizers; diff --git a/src/main/java/com/kingsrook/qbits/crm/email/model/EmailMessage.java b/src/main/java/com/kingsrook/qbits/crm/email/model/EmailMessage.java index d0d320d..99232ec 100644 --- a/src/main/java/com/kingsrook/qbits/crm/email/model/EmailMessage.java +++ b/src/main/java/com/kingsrook/qbits/crm/email/model/EmailMessage.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for the crm_email_message table. *******************************************************************************/ + package com.kingsrook.qbits.crm.email.model; @@ -36,7 +58,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.Tier; ) public class EmailMessage extends QRecordEntity { - public static final String TABLE_NAME = "crmEmailMessage"; + public static final String TABLE_NAME = "crm_email_message"; diff --git a/src/main/java/com/kingsrook/qbits/crm/email/model/EmailSequence.java b/src/main/java/com/kingsrook/qbits/crm/email/model/EmailSequence.java index 71c87d4..1ff5176 100644 --- a/src/main/java/com/kingsrook/qbits/crm/email/model/EmailSequence.java +++ b/src/main/java/com/kingsrook/qbits/crm/email/model/EmailSequence.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for EmailSequence table *******************************************************************************/ + package com.kingsrook.qbits.crm.email.model; @@ -47,7 +69,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.Tier; ) public class EmailSequence extends QRecordEntity { - public static final String TABLE_NAME = "crmEmailSequence"; + public static final String TABLE_NAME = "crm_email_sequence"; diff --git a/src/main/java/com/kingsrook/qbits/crm/email/model/EmailTemplate.java b/src/main/java/com/kingsrook/qbits/crm/email/model/EmailTemplate.java index 4943e14..951cb3b 100644 --- a/src/main/java/com/kingsrook/qbits/crm/email/model/EmailTemplate.java +++ b/src/main/java/com/kingsrook/qbits/crm/email/model/EmailTemplate.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for the crm_email_template table. *******************************************************************************/ + package com.kingsrook.qbits.crm.email.model; @@ -36,7 +58,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.Tier; ) public class EmailTemplate extends QRecordEntity { - public static final String TABLE_NAME = "crmEmailTemplate"; + public static final String TABLE_NAME = "crm_email_template"; diff --git a/src/main/java/com/kingsrook/qbits/crm/email/model/SequenceEnrollment.java b/src/main/java/com/kingsrook/qbits/crm/email/model/SequenceEnrollment.java index 5b4990c..a6ecb10 100644 --- a/src/main/java/com/kingsrook/qbits/crm/email/model/SequenceEnrollment.java +++ b/src/main/java/com/kingsrook/qbits/crm/email/model/SequenceEnrollment.java @@ -1,10 +1,33 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for SequenceEnrollment table *******************************************************************************/ + package com.kingsrook.qbits.crm.email.model; import java.time.Instant; +import java.util.List; import com.kingsrook.qbits.crm.core.model.enums.CrmEnrollmentStatus; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.data.QField; @@ -20,7 +43,6 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; import com.kingsrook.qqq.backend.core.model.metadata.tables.SectionFactory; import com.kingsrook.qqq.backend.core.model.metadata.tables.Tier; import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; -import java.util.List; /******************************************************************************* @@ -33,7 +55,7 @@ import java.util.List; ) public class SequenceEnrollment extends QRecordEntity { - public static final String TABLE_NAME = "crmSequenceEnrollment"; + public static final String TABLE_NAME = "crm_sequence_enrollment"; diff --git a/src/main/java/com/kingsrook/qbits/crm/email/model/SequenceStep.java b/src/main/java/com/kingsrook/qbits/crm/email/model/SequenceStep.java index 15364a5..9d8cd7c 100644 --- a/src/main/java/com/kingsrook/qbits/crm/email/model/SequenceStep.java +++ b/src/main/java/com/kingsrook/qbits/crm/email/model/SequenceStep.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for SequenceStep table *******************************************************************************/ + package com.kingsrook.qbits.crm.email.model; @@ -30,7 +52,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; ) public class SequenceStep extends QRecordEntity { - public static final String TABLE_NAME = "crmSequenceStep"; + public static final String TABLE_NAME = "crm_sequence_step"; diff --git a/src/main/java/com/kingsrook/qbits/crm/email/processes/EnrollInSequenceProcess.java b/src/main/java/com/kingsrook/qbits/crm/email/processes/EnrollInSequenceProcess.java index 1c4db3d..75c8d07 100644 --- a/src/main/java/com/kingsrook/qbits/crm/email/processes/EnrollInSequenceProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/email/processes/EnrollInSequenceProcess.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Process to enroll a contact in an email sequence. *******************************************************************************/ + package com.kingsrook.qbits.crm.email.processes; @@ -16,6 +38,7 @@ import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; +import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; @@ -28,7 +51,6 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; -import com.kingsrook.qqq.backend.core.model.data.QRecord; import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; @@ -47,7 +69,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; *******************************************************************************/ public class EnrollInSequenceProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "enrollInSequence"; + public static final String NAME = "crm_enroll_in_sequence"; @@ -168,7 +190,7 @@ public class EnrollInSequenceProcess implements BackendStep, MetaDataProducerInt .withCurrentStepNumber(0) .withStatus(CrmEnrollmentStatus.ACTIVE.getPossibleValueId()) .withEnrolledDate(Instant.now()) - .withEnrolledByUserId(input.getSession() != null ? input.getSession().getIdReference() : "system") + .withEnrolledByUserId(QContext.getQSession() != null ? QContext.getQSession().getIdReference() : "system") .withNextStepDate(nextStepDate) .withFailureCount(0); diff --git a/src/main/java/com/kingsrook/qbits/crm/email/processes/ProcessSequenceStepsProcess.java b/src/main/java/com/kingsrook/qbits/crm/email/processes/ProcessSequenceStepsProcess.java index abbf6da..adb4793 100644 --- a/src/main/java/com/kingsrook/qbits/crm/email/processes/ProcessSequenceStepsProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/email/processes/ProcessSequenceStepsProcess.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Scheduled process to execute pending email sequence steps. *******************************************************************************/ + package com.kingsrook.qbits.crm.email.processes; @@ -52,7 +74,7 @@ import com.kingsrook.qqq.backend.core.utils.StringUtils; *******************************************************************************/ public class ProcessSequenceStepsProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "processSequenceSteps"; + public static final String NAME = "crm_process_sequence_steps"; private static final int MAX_FAILURES = 3; @@ -212,6 +234,7 @@ public class ProcessSequenceStepsProcess implements BackendStep, MetaDataProduce { // just advance } + default -> throw (new QException("Unsupported sequence step type: " + stepType)); } } diff --git a/src/main/java/com/kingsrook/qbits/crm/email/processes/SendEmailProcess.java b/src/main/java/com/kingsrook/qbits/crm/email/processes/SendEmailProcess.java index 57146c2..3bb42ea 100644 --- a/src/main/java/com/kingsrook/qbits/crm/email/processes/SendEmailProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/email/processes/SendEmailProcess.java @@ -1,13 +1,36 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Process to send an email to a contact. Creates an Activity and an ** EmailMessage record, respecting doNotEmail flags and optional template ** lookups. *******************************************************************************/ + package com.kingsrook.qbits.crm.email.processes; import java.time.Instant; import java.util.List; +import com.kingsrook.qbits.crm.CrmSessionUtils; import com.kingsrook.qbits.crm.activities.model.Activity; import com.kingsrook.qbits.crm.activities.model.ActivityType; import com.kingsrook.qbits.crm.core.model.Contact; @@ -15,7 +38,6 @@ import com.kingsrook.qbits.crm.core.model.enums.CrmDirection; import com.kingsrook.qbits.crm.core.model.enums.CrmEmailStatus; import com.kingsrook.qbits.crm.email.model.EmailMessage; import com.kingsrook.qbits.crm.email.model.EmailTemplate; -import com.kingsrook.qbits.crm.CrmSessionUtils; import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; @@ -50,7 +72,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; *******************************************************************************/ public class SendEmailProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "sendEmail"; + public static final String NAME = "crm_send_email"; diff --git a/src/main/java/com/kingsrook/qbits/crm/email/processes/TrackEmailEventProcess.java b/src/main/java/com/kingsrook/qbits/crm/email/processes/TrackEmailEventProcess.java index 6371712..0a55d61 100644 --- a/src/main/java/com/kingsrook/qbits/crm/email/processes/TrackEmailEventProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/email/processes/TrackEmailEventProcess.java @@ -1,8 +1,30 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Process to track email engagement events (open, click, bounce, spam, reply). ** Updates the EmailMessage record counters and flags, and may set doNotEmail ** on the linked contact for hard bounces and spam complaints. *******************************************************************************/ + package com.kingsrook.qbits.crm.email.processes; @@ -43,7 +65,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; *******************************************************************************/ public class TrackEmailEventProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "trackEmailEvent"; + public static final String NAME = "crm_track_email_event"; @@ -155,7 +177,7 @@ public class TrackEmailEventProcess implements BackendStep, MetaDataProducerInte .withValue("status", CrmEnrollmentStatus.REPLIED.getPossibleValueId()); new UpdateAction().execute( - new UpdateInput("crmSequenceEnrollment").withRecord(enrollmentUpdate)); + new UpdateInput("crm_sequence_enrollment").withRecord(enrollmentUpdate)); } break; } diff --git a/src/main/java/com/kingsrook/qbits/crm/email/processes/UnenrollFromSequenceProcess.java b/src/main/java/com/kingsrook/qbits/crm/email/processes/UnenrollFromSequenceProcess.java index 4f6a688..1575600 100644 --- a/src/main/java/com/kingsrook/qbits/crm/email/processes/UnenrollFromSequenceProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/email/processes/UnenrollFromSequenceProcess.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Process to unenroll a contact from an email sequence. *******************************************************************************/ + package com.kingsrook.qbits.crm.email.processes; @@ -36,7 +58,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; *******************************************************************************/ public class UnenrollFromSequenceProcess implements BackendStep, MetaDataProducerInterface { - public static final String NAME = "unenrollFromSequence"; + public static final String NAME = "crm_unenroll_from_sequence"; diff --git a/src/main/java/com/kingsrook/qbits/crm/scoring/model/AssignmentRule.java b/src/main/java/com/kingsrook/qbits/crm/scoring/model/AssignmentRule.java index 30218d6..8efc816 100644 --- a/src/main/java/com/kingsrook/qbits/crm/scoring/model/AssignmentRule.java +++ b/src/main/java/com/kingsrook/qbits/crm/scoring/model/AssignmentRule.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for AssignmentRule table *******************************************************************************/ + package com.kingsrook.qbits.crm.scoring.model; @@ -41,7 +63,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.SectionFactory; ) public class AssignmentRule extends QRecordEntity { - public static final String TABLE_NAME = "crmAssignmentRule"; + public static final String TABLE_NAME = "crm_assignment_rule"; diff --git a/src/main/java/com/kingsrook/qbits/crm/scoring/model/AssignmentRuleMember.java b/src/main/java/com/kingsrook/qbits/crm/scoring/model/AssignmentRuleMember.java index 09f0508..9df68d3 100644 --- a/src/main/java/com/kingsrook/qbits/crm/scoring/model/AssignmentRuleMember.java +++ b/src/main/java/com/kingsrook/qbits/crm/scoring/model/AssignmentRuleMember.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for AssignmentRuleMember table *******************************************************************************/ + package com.kingsrook.qbits.crm.scoring.model; @@ -28,7 +50,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; ) public class AssignmentRuleMember extends QRecordEntity { - public static final String TABLE_NAME = "crmAssignmentRuleMember"; + public static final String TABLE_NAME = "crm_assignment_rule_member"; diff --git a/src/main/java/com/kingsrook/qbits/crm/scoring/model/LeadScoreRule.java b/src/main/java/com/kingsrook/qbits/crm/scoring/model/LeadScoreRule.java index a3c6609..2a5f8ce 100644 --- a/src/main/java/com/kingsrook/qbits/crm/scoring/model/LeadScoreRule.java +++ b/src/main/java/com/kingsrook/qbits/crm/scoring/model/LeadScoreRule.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for LeadScoreRule table *******************************************************************************/ + package com.kingsrook.qbits.crm.scoring.model; @@ -30,7 +52,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.SectionFactory; ) public class LeadScoreRule extends QRecordEntity { - public static final String TABLE_NAME = "crmLeadScoreRule"; + public static final String TABLE_NAME = "crm_lead_score_rule"; diff --git a/src/main/java/com/kingsrook/qbits/crm/scoring/model/SalesGoal.java b/src/main/java/com/kingsrook/qbits/crm/scoring/model/SalesGoal.java index 3a790f4..8978abc 100644 --- a/src/main/java/com/kingsrook/qbits/crm/scoring/model/SalesGoal.java +++ b/src/main/java/com/kingsrook/qbits/crm/scoring/model/SalesGoal.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for SalesGoal table *******************************************************************************/ + package com.kingsrook.qbits.crm.scoring.model; @@ -33,7 +55,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; ) public class SalesGoal extends QRecordEntity { - public static final String TABLE_NAME = "crmSalesGoal"; + public static final String TABLE_NAME = "crm_sales_goal"; diff --git a/src/main/java/com/kingsrook/qbits/crm/scoring/processes/AutoAssignProcess.java b/src/main/java/com/kingsrook/qbits/crm/scoring/processes/AutoAssignProcess.java index be77d24..4109134 100644 --- a/src/main/java/com/kingsrook/qbits/crm/scoring/processes/AutoAssignProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/scoring/processes/AutoAssignProcess.java @@ -1,10 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Process to auto-assign a contact or deal based on assignment rules. *******************************************************************************/ + package com.kingsrook.qbits.crm.scoring.processes; -import java.io.Serializable; import java.time.Instant; import java.util.Comparator; import java.util.List; @@ -43,7 +64,6 @@ import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon; import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData; import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMetaData; import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; -import com.kingsrook.qqq.backend.core.utils.CollectionUtils; import com.kingsrook.qqq.backend.core.utils.JsonUtils; import com.kingsrook.qqq.backend.core.utils.StringUtils; @@ -57,7 +77,7 @@ public class AutoAssignProcess implements BackendStep, MetaDataProducerInterface { private static final QLogger LOG = QLogger.getLogger(AutoAssignProcess.class); - public static final String NAME = "autoAssign"; + public static final String NAME = "crm_auto_assign"; diff --git a/src/main/java/com/kingsrook/qbits/crm/scoring/processes/CalculateLeadScoresProcess.java b/src/main/java/com/kingsrook/qbits/crm/scoring/processes/CalculateLeadScoresProcess.java index a25b9dc..9e06e56 100644 --- a/src/main/java/com/kingsrook/qbits/crm/scoring/processes/CalculateLeadScoresProcess.java +++ b/src/main/java/com/kingsrook/qbits/crm/scoring/processes/CalculateLeadScoresProcess.java @@ -1,11 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Scheduled process to calculate lead scores for all contacts. *******************************************************************************/ + package com.kingsrook.qbits.crm.scoring.processes; -import java.time.Instant; -import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Objects; import com.kingsrook.qbits.crm.core.model.Company; @@ -18,10 +38,10 @@ import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.logging.QLogger; -import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput; +import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput; +import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy; @@ -48,7 +68,7 @@ public class CalculateLeadScoresProcess implements BackendStep, MetaDataProducer { private static final QLogger LOG = QLogger.getLogger(CalculateLeadScoresProcess.class); - public static final String NAME = "calculateLeadScores"; + public static final String NAME = "crm_calculate_lead_scores"; diff --git a/src/main/java/com/kingsrook/qbits/crm/security/CrmPermissions.java b/src/main/java/com/kingsrook/qbits/crm/security/CrmPermissions.java new file mode 100644 index 0000000..cd8d462 --- /dev/null +++ b/src/main/java/com/kingsrook/qbits/crm/security/CrmPermissions.java @@ -0,0 +1,113 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package com.kingsrook.qbits.crm.security; + + +import java.util.List; +import java.util.Set; +import com.kingsrook.qqq.backend.core.model.metadata.permissions.DenyBehavior; +import com.kingsrook.qqq.backend.core.model.metadata.permissions.PermissionLevel; +import com.kingsrook.qqq.backend.core.model.metadata.permissions.QPermissionRules; + + +/******************************************************************************* + ** Standard QQQ permission suffixes for CRM data, settings and administration. + *******************************************************************************/ +public final class CrmPermissions +{ + public static final String BASE = "crm"; + public static final String MANAGE_BASE = "crm.manage"; + public static final String ADMIN_BASE = "crm.admin"; + public static final String APP_ACCESS = BASE + ".hasAccess"; + public static final String READ = BASE + ".read"; + public static final String WRITE = BASE + ".write"; + public static final String MANAGE = MANAGE_BASE + ".hasAccess"; + public static final String MANAGE_READ = MANAGE_BASE + ".read"; + public static final String MANAGE_WRITE = MANAGE_BASE + ".write"; + public static final String ADMIN = ADMIN_BASE + ".hasAccess"; + public static final String ADMIN_READ = ADMIN_BASE + ".read"; + public static final String ADMIN_WRITE = ADMIN_BASE + ".write"; + public static final List ALL = List.of(APP_ACCESS, READ, WRITE, MANAGE, MANAGE_READ, MANAGE_WRITE, ADMIN, ADMIN_READ, ADMIN_WRITE); + + private static final Set SETTINGS_TABLES = Set.of( + "crm_pipeline", "crm_product", "crm_email_template", "crm_email_sequence", + "crm_lead_score_rule", "crm_assignment_rule", "crm_sales_goal", "crm_lifecycle_stage", + "crm_lead_source", "crm_industry", "crm_activity_type", "crm_activity_outcome", + "crm_contact_role", "crm_win_loss_reason"); + + private static final Set MANAGEMENT_PROCESSES = Set.of( + "crm_merge_contacts", "crm_merge_companies", "crm_bulk_assign_owner", + "crm_subscribe_to_list", "crm_unsubscribe_from_list", "crm_enroll_in_sequence", + "crm_unenroll_from_sequence", "crm_process_sequence_steps"); + + + + /******************************************************************************* + ** Utility class. + *******************************************************************************/ + private CrmPermissions() + { + } + + + + /******************************************************************************* + ** Main and child data use CRM permissions; settings and currency are separate. + *******************************************************************************/ + public static QPermissionRules tableRules(String tableName) + { + String base = "crm_currency".equals(tableName) || SETTINGS_TABLES.contains(tableName) ? MANAGE_BASE : BASE; + return (rules(PermissionLevel.READ_WRITE_PERMISSIONS, base)); + } + + + + /******************************************************************************* + ** Erasure is administrative; management actions have a separate access grant. + *******************************************************************************/ + public static QPermissionRules processRules(String processName) + { + String base = "crm_gdpr_anonymize_contact".equals(processName) ? ADMIN_BASE : MANAGEMENT_PROCESSES.contains(processName) ? MANAGE_BASE : BASE; + return (hasAccessRules(base)); + } + + + + /******************************************************************************* + ** Processes and widgets use the standard hasAccess suffix. + *******************************************************************************/ + public static QPermissionRules hasAccessRules(String base) + { + return (rules(PermissionLevel.HAS_ACCESS_PERMISSION, base)); + } + + + + /******************************************************************************* + ** Set both protection and denial explicitly, independent of host defaults. + *******************************************************************************/ + private static QPermissionRules rules(PermissionLevel level, String base) + { + return (new QPermissionRules().withLevel(level).withPermissionBaseName(base).withDenyBehavior(DenyBehavior.HIDDEN)); + } + +} diff --git a/src/main/java/com/kingsrook/qbits/crm/sync/CrmCurrencyUtils.java b/src/main/java/com/kingsrook/qbits/crm/sync/CrmCurrencyUtils.java index 0b3cebd..7bbe1d4 100644 --- a/src/main/java/com/kingsrook/qbits/crm/sync/CrmCurrencyUtils.java +++ b/src/main/java/com/kingsrook/qbits/crm/sync/CrmCurrencyUtils.java @@ -1,7 +1,29 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Utility class for CRM currency conversion. Queries the Currency table for ** the exchange rate and converts an amount to the base currency. *******************************************************************************/ + package com.kingsrook.qbits.crm.sync; diff --git a/src/main/java/com/kingsrook/qbits/crm/sync/model/ExternalMapping.java b/src/main/java/com/kingsrook/qbits/crm/sync/model/ExternalMapping.java index 1ce9105..a7fff98 100644 --- a/src/main/java/com/kingsrook/qbits/crm/sync/model/ExternalMapping.java +++ b/src/main/java/com/kingsrook/qbits/crm/sync/model/ExternalMapping.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** QRecord Entity for the crm_external_mapping table. *******************************************************************************/ + package com.kingsrook.qbits.crm.sync.model; @@ -35,7 +57,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; ) public class ExternalMapping extends QRecordEntity { - public static final String TABLE_NAME = "crmExternalMapping"; + public static final String TABLE_NAME = "crm_external_mapping"; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmActivityCountRenderer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmActivityCountRenderer.java index eccf46d..f567a90 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmActivityCountRenderer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmActivityCountRenderer.java @@ -1,3 +1,24 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Renderer for the CRM Activity Count widget. ** @@ -5,6 +26,7 @@ ** produce counts. Returns a MultiStatisticsData with one entry per known ** type: Call, Email, Meeting. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmActivityCountWidgetProducer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmActivityCountWidgetProducer.java index 1e2c041..8d583a7 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmActivityCountWidgetProducer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmActivityCountWidgetProducer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** MetaData producer for the CRM Activity Count widget. ** ** Provides a MULTI_STATISTICS view showing counts of activities by type for ** the current user today: calls, emails, meetings. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -17,11 +39,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon; /******************************************************************************* - ** Produces metadata for the crmActivityCount widget (MULTI_STATISTICS type). + ** Produces metadata for the crm_activity_count widget (MULTI_STATISTICS type). *******************************************************************************/ public class CrmActivityCountWidgetProducer extends MetaDataProducer { - public static final String NAME = "crmActivityCount"; + public static final String NAME = "crm_activity_count"; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmActivityFeedRenderer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmActivityFeedRenderer.java index 63aa2ed..4f25bae 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmActivityFeedRenderer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmActivityFeedRenderer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Renderer for the CRM Activity Feed widget. ** ** Queries the most recent 50 activities (by createDate descending) and returns ** a table with columns: subject, activityType, contact, company, date. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmActivityFeedWidgetProducer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmActivityFeedWidgetProducer.java index 26b468c..aa4a762 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmActivityFeedWidgetProducer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmActivityFeedWidgetProducer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** MetaData producer for the CRM Activity Feed widget. ** ** Provides a TABLE view showing the most recent 50 activities across the CRM ** with columns: subject, activityType, contact, company, date. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -16,11 +38,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData; /******************************************************************************* - ** Produces metadata for the crmActivityFeed widget (TABLE type). + ** Produces metadata for the crm_activity_feed widget (TABLE type). *******************************************************************************/ public class CrmActivityFeedWidgetProducer extends MetaDataProducer { - public static final String NAME = "crmActivityFeed"; + public static final String NAME = "crm_activity_feed"; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmAvgDealSizeRenderer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmAvgDealSizeRenderer.java index 919efd0..9cca0e2 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmAvgDealSizeRenderer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmAvgDealSizeRenderer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Renderer for the Average Deal Size widget. ** ** Queries deals where actualCloseDate is set and stage is closedWon. ** Computes average amountInBaseCurrency and returns as a single-stat table. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmAvgDealSizeWidgetProducer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmAvgDealSizeWidgetProducer.java index 1895f57..1302d4b 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmAvgDealSizeWidgetProducer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmAvgDealSizeWidgetProducer.java @@ -1,8 +1,30 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** MetaData producer for the Average Deal Size widget. ** ** Shows the average amount of closed-won deals. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -15,11 +37,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData; /******************************************************************************* - ** Produces metadata for the crmAvgDealSize widget (TABLE type). + ** Produces metadata for the crm_avg_deal_size widget (TABLE type). *******************************************************************************/ public class CrmAvgDealSizeWidgetProducer extends MetaDataProducer { - public static final String NAME = "crmAvgDealSize"; + public static final String NAME = "crm_avg_deal_size"; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmContactTimelineRenderer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmContactTimelineRenderer.java index bfa8747..bc8490c 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmContactTimelineRenderer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmContactTimelineRenderer.java @@ -1,3 +1,24 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Renderer for the CRM Contact Timeline widget. ** @@ -5,6 +26,7 @@ ** a StepperData with each activity as a chronological step. Activities are ** ordered by createDate ascending. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmContactTimelineWidgetProducer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmContactTimelineWidgetProducer.java index 4dc6b84..efae2d1 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmContactTimelineWidgetProducer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmContactTimelineWidgetProducer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** MetaData producer for the CRM Contact Timeline widget. ** ** Provides a STEPPER view showing a chronological timeline of activities for ** a specific contact. The contactId is passed as a widget input parameter. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -17,11 +39,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon; /******************************************************************************* - ** Produces metadata for the crmContactTimeline widget (STEPPER type). + ** Produces metadata for the crm_contact_timeline widget (STEPPER type). *******************************************************************************/ public class CrmContactTimelineWidgetProducer extends MetaDataProducer { - public static final String NAME = "crmContactTimeline"; + public static final String NAME = "crm_contact_timeline"; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmDealForecastRenderer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmDealForecastRenderer.java index 14ef477..5c7c7ae 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmDealForecastRenderer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmDealForecastRenderer.java @@ -1,3 +1,24 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Renderer for the CRM Deal Forecast widget. ** @@ -5,6 +26,7 @@ ** month. Returns a table with columns: month, dealCount, totalAmount, ** totalWeightedAmount. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -13,7 +35,6 @@ import java.time.LocalDate; import java.time.YearMonth; import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmDealForecastWidgetProducer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmDealForecastWidgetProducer.java index 455d379..dd2a25d 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmDealForecastWidgetProducer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmDealForecastWidgetProducer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** MetaData producer for the CRM Deal Forecast widget. ** ** Provides a TABLE view showing open deals grouped by expected close month ** with counts, total amounts, and weighted amounts. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -16,11 +38,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData; /******************************************************************************* - ** Produces metadata for the crmDealForecast widget (TABLE type). + ** Produces metadata for the crm_deal_forecast widget (TABLE type). *******************************************************************************/ public class CrmDealForecastWidgetProducer extends MetaDataProducer { - public static final String NAME = "crmDealForecast"; + public static final String NAME = "crm_deal_forecast"; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmPipelineConversionRenderer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmPipelineConversionRenderer.java index a1e0318..f9ab5fe 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmPipelineConversionRenderer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmPipelineConversionRenderer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Renderer for the Pipeline Conversion widget. ** ** Queries DealStageHistory, counts transitions into each stage (entered) ** versus transitions out (progressed), and computes a conversion rate. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmPipelineConversionWidgetProducer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmPipelineConversionWidgetProducer.java index 3f34d4e..d12b11e 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmPipelineConversionWidgetProducer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmPipelineConversionWidgetProducer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** MetaData producer for the Pipeline Conversion widget. ** ** Shows conversion rates between pipeline stages based on DealStageHistory ** transition data. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -16,11 +38,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData; /******************************************************************************* - ** Produces metadata for the crmPipelineConversion widget (TABLE type). + ** Produces metadata for the crm_pipeline_conversion widget (TABLE type). *******************************************************************************/ public class CrmPipelineConversionWidgetProducer extends MetaDataProducer { - public static final String NAME = "crmPipelineConversion"; + public static final String NAME = "crm_pipeline_conversion"; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmPipelineSummaryRenderer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmPipelineSummaryRenderer.java index e7b1d14..6da9503 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmPipelineSummaryRenderer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmPipelineSummaryRenderer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Renderer for the CRM Pipeline Summary widget. ** ** Queries deals grouped by pipelineStageId for a given pipelineId and returns ** a table with columns: stageName, dealCount, totalAmount, weightedAmount. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmPipelineSummaryWidgetProducer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmPipelineSummaryWidgetProducer.java index 789664c..8dc0349 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmPipelineSummaryWidgetProducer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmPipelineSummaryWidgetProducer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** MetaData producer for the CRM Pipeline Summary widget. ** ** Provides a TABLE view showing deal counts and amounts grouped by pipeline ** stage for a given pipeline. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -16,11 +38,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData; /******************************************************************************* - ** Produces metadata for the crmPipelineSummary widget (TABLE type). + ** Produces metadata for the crm_pipeline_summary widget (TABLE type). *******************************************************************************/ public class CrmPipelineSummaryWidgetProducer extends MetaDataProducer { - public static final String NAME = "crmPipelineSummary"; + public static final String NAME = "crm_pipeline_summary"; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmQuotaAttainmentRenderer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmQuotaAttainmentRenderer.java index a73ace1..487110d 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmQuotaAttainmentRenderer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmQuotaAttainmentRenderer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Renderer for the CRM Quota Attainment widget. ** ** Queries the SalesGoal for the current user and current period, then queries ** won deals in that period to compute attainment percentage. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmQuotaAttainmentWidgetProducer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmQuotaAttainmentWidgetProducer.java index 38152e2..0f820e7 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmQuotaAttainmentWidgetProducer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmQuotaAttainmentWidgetProducer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** MetaData producer for the CRM Quota Attainment widget. ** ** Provides a MULTI_STATISTICS view showing quota attainment percentage for ** the current user and current period. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -17,11 +39,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon; /******************************************************************************* - ** Produces metadata for the crmQuotaAttainment widget (MULTI_STATISTICS type). + ** Produces metadata for the crm_quota_attainment widget (MULTI_STATISTICS type). *******************************************************************************/ public class CrmQuotaAttainmentWidgetProducer extends MetaDataProducer { - public static final String NAME = "crmQuotaAttainment"; + public static final String NAME = "crm_quota_attainment"; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmRecentDealsRenderer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmRecentDealsRenderer.java index ad34c97..7728157 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmRecentDealsRenderer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmRecentDealsRenderer.java @@ -1,3 +1,24 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Renderer for the Recent Deals widget. ** @@ -5,6 +26,7 @@ ** limited to 20 rows. Returns table with name, amount, owner, closedDate, ** winLossReason. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmRecentDealsWidgetProducer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmRecentDealsWidgetProducer.java index e8eeb71..2dfff5a 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmRecentDealsWidgetProducer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmRecentDealsWidgetProducer.java @@ -1,8 +1,30 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** MetaData producer for the Recent Deals widget. ** ** Shows the most recently closed deals with key details. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -15,11 +37,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData; /******************************************************************************* - ** Produces metadata for the crmRecentDeals widget (TABLE type). + ** Produces metadata for the crm_recent_deals widget (TABLE type). *******************************************************************************/ public class CrmRecentDealsWidgetProducer extends MetaDataProducer { - public static final String NAME = "crmRecentDeals"; + public static final String NAME = "crm_recent_deals"; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmRottingDealsRenderer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmRottingDealsRenderer.java index a77731f..541b156 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmRottingDealsRenderer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmRottingDealsRenderer.java @@ -1,3 +1,24 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Renderer for the CRM Rotting Deals widget. ** @@ -6,6 +27,7 @@ ** Returns a table with columns: dealName, stageName, daysInStage, rotDays, ** ownerUserId, amount. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmRottingDealsWidgetProducer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmRottingDealsWidgetProducer.java index 60a5e8e..99cb3ae 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmRottingDealsWidgetProducer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmRottingDealsWidgetProducer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** MetaData producer for the CRM Rotting Deals widget. ** ** Provides a TABLE view showing deals that have exceeded their current ** stage's rotDays threshold, indicating they need attention. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -16,11 +38,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData; /******************************************************************************* - ** Produces metadata for the crmRottingDeals widget (TABLE type). + ** Produces metadata for the crm_rotting_deals widget (TABLE type). *******************************************************************************/ public class CrmRottingDealsWidgetProducer extends MetaDataProducer { - public static final String NAME = "crmRottingDeals"; + public static final String NAME = "crm_rotting_deals"; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmSalesCycleLengthRenderer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmSalesCycleLengthRenderer.java index c9defa7..52a56cc 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmSalesCycleLengthRenderer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmSalesCycleLengthRenderer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Renderer for the Sales Cycle Length widget. ** ** Queries closedWon deals and computes the average number of days from ** createDate to actualCloseDate. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmSalesCycleLengthWidgetProducer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmSalesCycleLengthWidgetProducer.java index e93acae..0da6b3f 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmSalesCycleLengthWidgetProducer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmSalesCycleLengthWidgetProducer.java @@ -1,8 +1,30 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** MetaData producer for the Sales Cycle Length widget. ** ** Shows the average number of days from deal creation to close for won deals. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -15,11 +37,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData; /******************************************************************************* - ** Produces metadata for the crmSalesCycleLength widget (TABLE type). + ** Produces metadata for the crm_sales_cycle_length widget (TABLE type). *******************************************************************************/ public class CrmSalesCycleLengthWidgetProducer extends MetaDataProducer { - public static final String NAME = "crmSalesCycleLength"; + public static final String NAME = "crm_sales_cycle_length"; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmSalesLeaderboardRenderer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmSalesLeaderboardRenderer.java index bc4101d..fe1eb92 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmSalesLeaderboardRenderer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmSalesLeaderboardRenderer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Renderer for the CRM Sales Leaderboard widget. ** ** Queries deals in closed-won stages, groups by ownerUserId, sums ** amountInBaseCurrency, and returns a ranked table. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmSalesLeaderboardWidgetProducer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmSalesLeaderboardWidgetProducer.java index ba6f9e7..92c992c 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmSalesLeaderboardWidgetProducer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmSalesLeaderboardWidgetProducer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** MetaData producer for the CRM Sales Leaderboard widget. ** ** Provides a TABLE view showing deals grouped by owner with total revenue ** from closed-won deals, ranked descending. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -17,11 +39,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon; /******************************************************************************* - ** Produces metadata for the crmSalesLeaderboard widget (TABLE type). + ** Produces metadata for the crm_sales_leaderboard widget (TABLE type). *******************************************************************************/ public class CrmSalesLeaderboardWidgetProducer extends MetaDataProducer { - public static final String NAME = "crmSalesLeaderboard"; + public static final String NAME = "crm_sales_leaderboard"; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmStageDurationRenderer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmStageDurationRenderer.java index 5aadc9e..e22b0d0 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmStageDurationRenderer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmStageDurationRenderer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Renderer for the Stage Duration widget. ** ** Queries DealStageHistory where durationInFromStageDays is not null, ** computes average and median per fromStageId. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmStageDurationWidgetProducer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmStageDurationWidgetProducer.java index c02af18..b824858 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmStageDurationWidgetProducer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmStageDurationWidgetProducer.java @@ -1,8 +1,30 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** MetaData producer for the Stage Duration widget. ** ** Shows average and median days spent in each pipeline stage. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -15,11 +37,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData; /******************************************************************************* - ** Produces metadata for the crmStageDuration widget (TABLE type). + ** Produces metadata for the crm_stage_duration widget (TABLE type). *******************************************************************************/ public class CrmStageDurationWidgetProducer extends MetaDataProducer { - public static final String NAME = "crmStageDuration"; + public static final String NAME = "crm_stage_duration"; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmWidgetMetaData.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmWidgetMetaData.java new file mode 100644 index 0000000..e482cab --- /dev/null +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmWidgetMetaData.java @@ -0,0 +1,101 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package com.kingsrook.qbits.crm.widgets; + + +import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.qbits.SourceQBitAware; + + +/******************************************************************************* + ** QQQ 4.1.0-RC.6 widgets lack SourceQBitAware. Preserve their metadata while + ** supplying the same provenance interface as tables and processes. + ** Remove this adapter when QWidgetMetaData implements SourceQBitAware. + *******************************************************************************/ +public class CrmWidgetMetaData extends QWidgetMetaData implements SourceQBitAware +{ + private String sourceQBitName; + + + + /******************************************************************************* + ** Copy the produced widget without losing renderer settings or validation. + *******************************************************************************/ + public CrmWidgetMetaData(QWidgetMetaData widget) + { + setName(widget.getName()); + setIcon(widget.getIcon()); + setLabel(widget.getLabel()); + setTooltip(widget.getTooltip()); + setType(widget.getType()); + setMinHeight(widget.getMinHeight()); + setFooterHTML(widget.getFooterHTML()); + setIsCard(widget.getIsCard()); + setGridColumns(widget.getGridColumns()); + setCodeReference(widget.getCodeReference()); + setPermissionRules(widget.getPermissionRules()); + setDropdowns(widget.getDropdowns()); + setStoreDropdownSelections(widget.getStoreDropdownSelections()); + setShowReloadButton(widget.getShowReloadButton()); + setShowExportButton(widget.getShowExportButton()); + setIcons(widget.getIcons()); + setHelpContent(widget.getHelpContent()); + setDefaultValues(widget.getDefaultValues()); + setValidatorPlugin(widget.getValidatorPlugin()); + setCollapsible(widget.getCollapsible()); + } + + + + /******************************************************************************* + ** Source QBit identifier. + *******************************************************************************/ + @Override + public String getSourceQBitName() + { + return (sourceQBitName); + } + + + + /******************************************************************************* + ** Set the source QBit identifier. + *******************************************************************************/ + @Override + public void setSourceQBitName(String sourceQBitName) + { + this.sourceQBitName = sourceQBitName; + } + + + + /******************************************************************************* + ** Fluent source QBit identifier. + *******************************************************************************/ + @Override + public CrmWidgetMetaData withSourceQBitName(String sourceQBitName) + { + setSourceQBitName(sourceQBitName); + return (this); + } + +} diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmWinRateRenderer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmWinRateRenderer.java index a1aa69c..b829377 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmWinRateRenderer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmWinRateRenderer.java @@ -1,9 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Renderer for the Win Rate widget. ** ** Queries DealStageHistory for transitions to closedWon and closedLost stages, ** groups by month, and computes win rate percentage. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -13,7 +35,6 @@ import java.time.Instant; import java.time.YearMonth; import java.time.ZoneId; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -24,9 +45,6 @@ import com.kingsrook.qbits.crm.deals.model.PipelineStage; import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput; diff --git a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmWinRateWidgetProducer.java b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmWinRateWidgetProducer.java index a285b8b..ae4028b 100644 --- a/src/main/java/com/kingsrook/qbits/crm/widgets/CrmWinRateWidgetProducer.java +++ b/src/main/java/com/kingsrook/qbits/crm/widgets/CrmWinRateWidgetProducer.java @@ -1,8 +1,30 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** MetaData producer for the Win Rate widget. ** ** Shows won/lost counts and win rate percentage grouped by month. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -15,11 +37,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData; /******************************************************************************* - ** Produces metadata for the crmWinRate widget (TABLE type). + ** Produces metadata for the crm_win_rate widget (TABLE type). *******************************************************************************/ public class CrmWinRateWidgetProducer extends MetaDataProducer { - public static final String NAME = "crmWinRate"; + public static final String NAME = "crm_win_rate"; diff --git a/src/main/resources/db/liquibase/qbit-crm/crm.changelog.sql b/src/main/resources/db/liquibase/qbit-crm/crm.changelog.sql new file mode 100644 index 0000000..ecdf177 --- /dev/null +++ b/src/main/resources/db/liquibase/qbit-crm/crm.changelog.sql @@ -0,0 +1,640 @@ +--liquibase formatted sql +-- Copyright 2026 Kingsrook, LLC. Licensed under the Apache License, Version 2.0. +-- https://www.apache.org/licenses/LICENSE-2.0 +-- QBit CRM 0.2.0 P1 PostgreSQL reference schema (33 tables). +-- QQQ table names equal SQL names; Java field names map to snake_case columns. +-- Unique constraints match QQQ metadata. Relationship columns are indexed; +-- foreign-key constraints are deliberately not imposed (the QQQ/host layer owns +-- validation and deletion policy, including polymorphic and optional references). +-- Optional host-configured securityFields require matching host-managed columns. + +--changeset qbit-crm:020-crm_activity +CREATE TABLE IF NOT EXISTS crm_activity ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + activity_type_id INTEGER NOT NULL, + subject VARCHAR(500) NOT NULL, + description TEXT, + contact_id INTEGER, + company_id INTEGER, + deal_id INTEGER, + owner_user_id TEXT NOT NULL, + assigned_to_user_id TEXT, + start_date TIMESTAMP WITHOUT TIME ZONE, + end_date TIMESTAMP WITHOUT TIME ZONE, + due_date TIMESTAMP WITHOUT TIME ZONE, + completed_date TIMESTAMP WITHOUT TIME ZONE, + is_completed BOOLEAN DEFAULT FALSE NOT NULL, + priority INTEGER, + duration_minutes INTEGER, + outcome_id INTEGER, + location VARCHAR(500), + conference_link VARCHAR(1000), + direction INTEGER, + is_reminder_set BOOLEAN DEFAULT FALSE, + reminder_date TIMESTAMP WITHOUT TIME ZONE, + external_calendar_id VARCHAR(500), + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE +); + +CREATE INDEX IF NOT EXISTS ix_crm_activity_activity_type_id ON crm_activity (activity_type_id); +CREATE INDEX IF NOT EXISTS ix_crm_activity_contact_id ON crm_activity (contact_id); +CREATE INDEX IF NOT EXISTS ix_crm_activity_company_id ON crm_activity (company_id); +CREATE INDEX IF NOT EXISTS ix_crm_activity_deal_id ON crm_activity (deal_id); +CREATE INDEX IF NOT EXISTS ix_crm_activity_owner_user_id ON crm_activity (owner_user_id); +CREATE INDEX IF NOT EXISTS ix_crm_activity_assigned_to_user_id ON crm_activity (assigned_to_user_id); +CREATE INDEX IF NOT EXISTS ix_crm_activity_outcome_id ON crm_activity (outcome_id); +CREATE INDEX IF NOT EXISTS ix_crm_activity_external_calendar_id ON crm_activity (external_calendar_id); + +--changeset qbit-crm:020-crm_activity_outcome +CREATE TABLE IF NOT EXISTS crm_activity_outcome ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + activity_type_id INTEGER NOT NULL, + name VARCHAR(100) NOT NULL, + sort_order INTEGER NOT NULL, + is_active BOOLEAN DEFAULT TRUE NOT NULL, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_activity_outcome_1 UNIQUE (activity_type_id, name) +); + +CREATE INDEX IF NOT EXISTS ix_crm_activity_outcome_activity_type_id ON crm_activity_outcome (activity_type_id); + +--changeset qbit-crm:020-crm_activity_participant +CREATE TABLE IF NOT EXISTS crm_activity_participant ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + activity_id INTEGER NOT NULL, + contact_id INTEGER, + user_id TEXT, + role INTEGER, + create_date TIMESTAMP WITHOUT TIME ZONE +); + +CREATE INDEX IF NOT EXISTS ix_crm_activity_participant_activity_id ON crm_activity_participant (activity_id); +CREATE INDEX IF NOT EXISTS ix_crm_activity_participant_contact_id ON crm_activity_participant (contact_id); +CREATE INDEX IF NOT EXISTS ix_crm_activity_participant_user_id ON crm_activity_participant (user_id); + +--changeset qbit-crm:020-crm_activity_type +CREATE TABLE IF NOT EXISTS crm_activity_type ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(100) NOT NULL, + icon_name VARCHAR(50), + is_system BOOLEAN DEFAULT FALSE NOT NULL, + sort_order INTEGER NOT NULL, + is_active BOOLEAN DEFAULT TRUE NOT NULL, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_activity_type_1 UNIQUE (name) +); + +--changeset qbit-crm:020-crm_assignment_rule +CREATE TABLE IF NOT EXISTS crm_assignment_rule ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(250) NOT NULL, + description TEXT, + entity_type INTEGER NOT NULL, + criteria_json TEXT, + assign_strategy INTEGER NOT NULL, + assign_to_user_id TEXT, + is_active BOOLEAN DEFAULT TRUE NOT NULL, + sort_order INTEGER NOT NULL, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE +); + +CREATE INDEX IF NOT EXISTS ix_crm_assignment_rule_assign_to_user_id ON crm_assignment_rule (assign_to_user_id); + +--changeset qbit-crm:020-crm_assignment_rule_member +CREATE TABLE IF NOT EXISTS crm_assignment_rule_member ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + assignment_rule_id INTEGER NOT NULL, + user_id TEXT NOT NULL, + sort_order INTEGER NOT NULL, + is_active BOOLEAN DEFAULT TRUE NOT NULL, + last_assigned_date TIMESTAMP WITHOUT TIME ZONE, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_assignment_rule_member_1 UNIQUE (assignment_rule_id, user_id) +); + +CREATE INDEX IF NOT EXISTS ix_crm_assignment_rule_member_assignment_rule_id ON crm_assignment_rule_member (assignment_rule_id); +CREATE INDEX IF NOT EXISTS ix_crm_assignment_rule_member_user_id ON crm_assignment_rule_member (user_id); + +--changeset qbit-crm:020-crm_company +CREATE TABLE IF NOT EXISTS crm_company ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(250) NOT NULL, + domain VARCHAR(250), + company_type INTEGER, + industry_id INTEGER, + employee_count INTEGER, + annual_revenue DECIMAL(20,6), + annual_revenue_currency_code VARCHAR(3) DEFAULT 'USD', + phone VARCHAR(50), + website VARCHAR(500), + address_line1 VARCHAR(250), + address_line2 VARCHAR(250), + city VARCHAR(100), + state VARCHAR(100), + postal_code VARCHAR(20), + country VARCHAR(100), + owner_user_id TEXT NOT NULL, + parent_company_id INTEGER, + description TEXT, + last_activity_date TIMESTAMP WITHOUT TIME ZONE, + last_contacted_date TIMESTAMP WITHOUT TIME ZONE, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE +); + +CREATE INDEX IF NOT EXISTS ix_crm_company_industry_id ON crm_company (industry_id); +CREATE INDEX IF NOT EXISTS ix_crm_company_owner_user_id ON crm_company (owner_user_id); +CREATE INDEX IF NOT EXISTS ix_crm_company_parent_company_id ON crm_company (parent_company_id); + +--changeset qbit-crm:020-crm_consent_record +CREATE TABLE IF NOT EXISTS crm_consent_record ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + contact_id INTEGER NOT NULL, + consent_type INTEGER NOT NULL, + status INTEGER NOT NULL, + legal_basis INTEGER, + source VARCHAR(250), + consent_date TIMESTAMP WITHOUT TIME ZONE NOT NULL, + expiry_date TIMESTAMP WITHOUT TIME ZONE, + ip_address VARCHAR(45), + create_date TIMESTAMP WITHOUT TIME ZONE +); + +CREATE INDEX IF NOT EXISTS ix_crm_consent_record_contact_id ON crm_consent_record (contact_id); + +--changeset qbit-crm:020-crm_contact +CREATE TABLE IF NOT EXISTS crm_contact ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + first_name VARCHAR(100) NOT NULL, + last_name VARCHAR(100) NOT NULL, + email VARCHAR(250), + secondary_email VARCHAR(250), + phone VARCHAR(50), + mobile_phone VARCHAR(50), + job_title VARCHAR(150), + department VARCHAR(100), + company_id INTEGER, + lifecycle_stage_id INTEGER, + lead_source_id INTEGER, + owner_user_id TEXT NOT NULL, + address_line1 VARCHAR(250), + address_line2 VARCHAR(250), + city VARCHAR(100), + state VARCHAR(100), + postal_code VARCHAR(20), + country VARCHAR(100), + timezone VARCHAR(50), + preferred_language VARCHAR(10), + website VARCHAR(500), + linkedin_url VARCHAR(500), + description TEXT, + lead_score INTEGER DEFAULT 0, + do_not_email BOOLEAN DEFAULT FALSE, + do_not_call BOOLEAN DEFAULT FALSE, + unsubscribe_date TIMESTAMP WITHOUT TIME ZONE, + last_activity_date TIMESTAMP WITHOUT TIME ZONE, + last_contacted_date TIMESTAMP WITHOUT TIME ZONE, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE +); + +CREATE INDEX IF NOT EXISTS ix_crm_contact_company_id ON crm_contact (company_id); +CREATE INDEX IF NOT EXISTS ix_crm_contact_lifecycle_stage_id ON crm_contact (lifecycle_stage_id); +CREATE INDEX IF NOT EXISTS ix_crm_contact_lead_source_id ON crm_contact (lead_source_id); +CREATE INDEX IF NOT EXISTS ix_crm_contact_owner_user_id ON crm_contact (owner_user_id); + +--changeset qbit-crm:020-crm_contact_role +CREATE TABLE IF NOT EXISTS crm_contact_role ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(100) NOT NULL, + sort_order INTEGER NOT NULL, + is_active BOOLEAN DEFAULT TRUE NOT NULL, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_contact_role_1 UNIQUE (name) +); + +--changeset qbit-crm:020-crm_currency +CREATE TABLE IF NOT EXISTS crm_currency ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + currency_code VARCHAR(3) NOT NULL, + name VARCHAR(100) NOT NULL, + symbol VARCHAR(5), + exchange_rate_to_base DECIMAL(20,6) DEFAULT 1.0 NOT NULL, + is_base_currency BOOLEAN DEFAULT FALSE NOT NULL, + is_active BOOLEAN DEFAULT TRUE NOT NULL, + rate_last_updated_date TIMESTAMP WITHOUT TIME ZONE, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_currency_1 UNIQUE (currency_code) +); + +--changeset qbit-crm:020-crm_deal +CREATE TABLE IF NOT EXISTS crm_deal ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(250) NOT NULL, + pipeline_id INTEGER NOT NULL, + pipeline_stage_id INTEGER NOT NULL, + amount DECIMAL(20,6), + currency_code VARCHAR(3) DEFAULT 'USD', + amount_in_base_currency DECIMAL(20,6), + probability_override_pct INTEGER, + weighted_amount DECIMAL(20,6), + company_id INTEGER, + owner_user_id TEXT NOT NULL, + lead_source_id INTEGER, + expected_close_date DATE, + actual_close_date DATE, + win_loss_reason_id INTEGER, + stage_entered_date TIMESTAMP WITHOUT TIME ZONE, + description TEXT, + priority INTEGER, + last_activity_date TIMESTAMP WITHOUT TIME ZONE, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE +); + +CREATE INDEX IF NOT EXISTS ix_crm_deal_pipeline_id ON crm_deal (pipeline_id); +CREATE INDEX IF NOT EXISTS ix_crm_deal_pipeline_stage_id ON crm_deal (pipeline_stage_id); +CREATE INDEX IF NOT EXISTS ix_crm_deal_company_id ON crm_deal (company_id); +CREATE INDEX IF NOT EXISTS ix_crm_deal_owner_user_id ON crm_deal (owner_user_id); +CREATE INDEX IF NOT EXISTS ix_crm_deal_lead_source_id ON crm_deal (lead_source_id); +CREATE INDEX IF NOT EXISTS ix_crm_deal_win_loss_reason_id ON crm_deal (win_loss_reason_id); + +--changeset qbit-crm:020-crm_deal_contact +CREATE TABLE IF NOT EXISTS crm_deal_contact ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + deal_id INTEGER NOT NULL, + contact_id INTEGER NOT NULL, + contact_role_id INTEGER, + is_primary BOOLEAN DEFAULT FALSE NOT NULL, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_deal_contact_1 UNIQUE (deal_id, contact_id) +); + +CREATE INDEX IF NOT EXISTS ix_crm_deal_contact_deal_id ON crm_deal_contact (deal_id); +CREATE INDEX IF NOT EXISTS ix_crm_deal_contact_contact_id ON crm_deal_contact (contact_id); +CREATE INDEX IF NOT EXISTS ix_crm_deal_contact_contact_role_id ON crm_deal_contact (contact_role_id); + +--changeset qbit-crm:020-crm_deal_product +CREATE TABLE IF NOT EXISTS crm_deal_product ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + deal_id INTEGER NOT NULL, + product_id INTEGER NOT NULL, + quantity DECIMAL(20,6) DEFAULT 1 NOT NULL, + unit_price DECIMAL(20,6) NOT NULL, + discount_pct DECIMAL(20,6) DEFAULT 0, + total_amount DECIMAL(20,6), + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE +); + +CREATE INDEX IF NOT EXISTS ix_crm_deal_product_deal_id ON crm_deal_product (deal_id); +CREATE INDEX IF NOT EXISTS ix_crm_deal_product_product_id ON crm_deal_product (product_id); + +--changeset qbit-crm:020-crm_deal_stage_history +CREATE TABLE IF NOT EXISTS crm_deal_stage_history ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + deal_id INTEGER NOT NULL, + from_stage_id INTEGER, + to_stage_id INTEGER NOT NULL, + user_id TEXT NOT NULL, + transition_date TIMESTAMP WITHOUT TIME ZONE NOT NULL, + duration_in_from_stage_days INTEGER, + create_date TIMESTAMP WITHOUT TIME ZONE +); + +CREATE INDEX IF NOT EXISTS ix_crm_deal_stage_history_deal_id ON crm_deal_stage_history (deal_id); +CREATE INDEX IF NOT EXISTS ix_crm_deal_stage_history_from_stage_id ON crm_deal_stage_history (from_stage_id); +CREATE INDEX IF NOT EXISTS ix_crm_deal_stage_history_to_stage_id ON crm_deal_stage_history (to_stage_id); +CREATE INDEX IF NOT EXISTS ix_crm_deal_stage_history_user_id ON crm_deal_stage_history (user_id); + +--changeset qbit-crm:020-crm_email_list +CREATE TABLE IF NOT EXISTS crm_email_list ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(250) NOT NULL, + slug VARCHAR(100) NOT NULL, + description TEXT, + is_active BOOLEAN DEFAULT TRUE NOT NULL, + is_public BOOLEAN DEFAULT TRUE NOT NULL, + sort_order INTEGER NOT NULL, + member_count INTEGER DEFAULT 0, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_email_list_1 UNIQUE (name), + CONSTRAINT uq_crm_email_list_2 UNIQUE (slug) +); + +--changeset qbit-crm:020-crm_email_list_member +CREATE TABLE IF NOT EXISTS crm_email_list_member ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + email_list_id INTEGER NOT NULL, + contact_id INTEGER, + email VARCHAR(250) NOT NULL, + first_name VARCHAR(100), + status INTEGER DEFAULT 1 NOT NULL, + subscribed_date TIMESTAMP WITHOUT TIME ZONE NOT NULL, + unsubscribed_date TIMESTAMP WITHOUT TIME ZONE, + subscription_source VARCHAR(250), + form_submission_id INTEGER, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_email_list_member_1 UNIQUE (email_list_id, email) +); + +CREATE INDEX IF NOT EXISTS ix_crm_email_list_member_email_list_id ON crm_email_list_member (email_list_id); +CREATE INDEX IF NOT EXISTS ix_crm_email_list_member_contact_id ON crm_email_list_member (contact_id); +CREATE INDEX IF NOT EXISTS ix_crm_email_list_member_form_submission_id ON crm_email_list_member (form_submission_id); + +--changeset qbit-crm:020-crm_email_message +CREATE TABLE IF NOT EXISTS crm_email_message ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + activity_id INTEGER, + from_address VARCHAR(250) NOT NULL, + from_name VARCHAR(100), + to_addresses TEXT NOT NULL, + cc_addresses TEXT, + bcc_addresses TEXT, + subject VARCHAR(500) NOT NULL, + body_html TEXT, + body_text TEXT, + sent_date TIMESTAMP WITHOUT TIME ZONE, + thread_id VARCHAR(250), + email_template_id INTEGER, + sequence_enrollment_id INTEGER, + direction INTEGER NOT NULL, + status INTEGER, + is_tracked BOOLEAN DEFAULT TRUE, + open_count INTEGER DEFAULT 0, + click_count INTEGER DEFAULT 0, + first_opened_date TIMESTAMP WITHOUT TIME ZONE, + first_clicked_date TIMESTAMP WITHOUT TIME ZONE, + bounce_type INTEGER, + is_spam_complaint BOOLEAN DEFAULT FALSE, + reply_to_email_id INTEGER, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE +); + +CREATE INDEX IF NOT EXISTS ix_crm_email_message_activity_id ON crm_email_message (activity_id); +CREATE INDEX IF NOT EXISTS ix_crm_email_message_thread_id ON crm_email_message (thread_id); +CREATE INDEX IF NOT EXISTS ix_crm_email_message_email_template_id ON crm_email_message (email_template_id); +CREATE INDEX IF NOT EXISTS ix_crm_email_message_sequence_enrollment_id ON crm_email_message (sequence_enrollment_id); +CREATE INDEX IF NOT EXISTS ix_crm_email_message_reply_to_email_id ON crm_email_message (reply_to_email_id); + +--changeset qbit-crm:020-crm_email_sequence +CREATE TABLE IF NOT EXISTS crm_email_sequence ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(250) NOT NULL, + description TEXT, + owner_user_id TEXT NOT NULL, + is_active BOOLEAN DEFAULT TRUE NOT NULL, + total_steps INTEGER, + business_days_only BOOLEAN DEFAULT TRUE NOT NULL, + send_window_start_hour INTEGER, + send_window_end_hour INTEGER, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE +); + +CREATE INDEX IF NOT EXISTS ix_crm_email_sequence_owner_user_id ON crm_email_sequence (owner_user_id); + +--changeset qbit-crm:020-crm_email_template +CREATE TABLE IF NOT EXISTS crm_email_template ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(250) NOT NULL, + subject VARCHAR(500) NOT NULL, + body_html TEXT NOT NULL, + body_text TEXT, + category VARCHAR(100), + owner_user_id TEXT NOT NULL, + is_shared BOOLEAN DEFAULT FALSE NOT NULL, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE +); + +CREATE INDEX IF NOT EXISTS ix_crm_email_template_owner_user_id ON crm_email_template (owner_user_id); + +--changeset qbit-crm:020-crm_external_mapping +CREATE TABLE IF NOT EXISTS crm_external_mapping ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + entity_type INTEGER NOT NULL, + entity_id INTEGER NOT NULL, + external_system VARCHAR(100) NOT NULL, + external_id VARCHAR(500) NOT NULL, + last_sync_date TIMESTAMP WITHOUT TIME ZONE, + sync_status INTEGER, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_external_mapping_1 UNIQUE (entity_type, entity_id, external_system) +); + +CREATE INDEX IF NOT EXISTS ix_crm_external_mapping_entity_id ON crm_external_mapping (entity_id); +CREATE INDEX IF NOT EXISTS ix_crm_external_mapping_external_id ON crm_external_mapping (external_id); + +--changeset qbit-crm:020-crm_form_submission +CREATE TABLE IF NOT EXISTS crm_form_submission ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + form_type INTEGER NOT NULL, + email VARCHAR(250) NOT NULL, + first_name VARCHAR(100), + last_name VARCHAR(100), + company VARCHAR(250), + phone VARCHAR(50), + message TEXT, + source_url VARCHAR(1000), + utm_source VARCHAR(250), + utm_medium VARCHAR(250), + utm_campaign VARCHAR(250), + utm_term VARCHAR(250), + utm_content VARCHAR(250), + referrer VARCHAR(1000), + contact_id INTEGER, + conversion_status INTEGER DEFAULT 1 NOT NULL, + converted_date TIMESTAMP WITHOUT TIME ZONE, + converted_by_user_id TEXT, + ip_address VARCHAR(45), + user_agent VARCHAR(500), + metadata TEXT, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE +); + +CREATE INDEX IF NOT EXISTS ix_crm_form_submission_contact_id ON crm_form_submission (contact_id); +CREATE INDEX IF NOT EXISTS ix_crm_form_submission_converted_by_user_id ON crm_form_submission (converted_by_user_id); + +--changeset qbit-crm:020-crm_industry +CREATE TABLE IF NOT EXISTS crm_industry ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(100) NOT NULL, + sort_order INTEGER NOT NULL, + is_active BOOLEAN DEFAULT TRUE NOT NULL, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_industry_1 UNIQUE (name) +); + +--changeset qbit-crm:020-crm_lead_score_rule +CREATE TABLE IF NOT EXISTS crm_lead_score_rule ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(250) NOT NULL, + description TEXT, + entity_type INTEGER NOT NULL, + field_path VARCHAR(250) NOT NULL, + operator INTEGER NOT NULL, + field_value VARCHAR(500), + score_adjustment INTEGER NOT NULL, + is_active BOOLEAN DEFAULT TRUE NOT NULL, + sort_order INTEGER NOT NULL, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE +); + +--changeset qbit-crm:020-crm_lead_source +CREATE TABLE IF NOT EXISTS crm_lead_source ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(100) NOT NULL, + sort_order INTEGER NOT NULL, + is_active BOOLEAN DEFAULT TRUE NOT NULL, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_lead_source_1 UNIQUE (name) +); + +--changeset qbit-crm:020-crm_lifecycle_stage +CREATE TABLE IF NOT EXISTS crm_lifecycle_stage ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(100) NOT NULL, + sort_order INTEGER NOT NULL, + is_active BOOLEAN DEFAULT TRUE NOT NULL, + description VARCHAR(500), + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_lifecycle_stage_1 UNIQUE (name) +); + +--changeset qbit-crm:020-crm_pipeline +CREATE TABLE IF NOT EXISTS crm_pipeline ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(100) NOT NULL, + description VARCHAR(500), + is_default BOOLEAN DEFAULT FALSE NOT NULL, + is_active BOOLEAN DEFAULT TRUE NOT NULL, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_pipeline_1 UNIQUE (name) +); + +--changeset qbit-crm:020-crm_pipeline_stage +CREATE TABLE IF NOT EXISTS crm_pipeline_stage ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + pipeline_id INTEGER NOT NULL, + name VARCHAR(100) NOT NULL, + sort_order INTEGER NOT NULL, + probability_pct INTEGER DEFAULT 0 NOT NULL, + rot_days INTEGER, + required_fields_json TEXT, + is_closed_won BOOLEAN DEFAULT FALSE NOT NULL, + is_closed_lost BOOLEAN DEFAULT FALSE NOT NULL, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_pipeline_stage_1 UNIQUE (pipeline_id, name), + CONSTRAINT uq_crm_pipeline_stage_2 UNIQUE (pipeline_id, sort_order) +); + +CREATE INDEX IF NOT EXISTS ix_crm_pipeline_stage_pipeline_id ON crm_pipeline_stage (pipeline_id); + +--changeset qbit-crm:020-crm_product +CREATE TABLE IF NOT EXISTS crm_product ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(250) NOT NULL, + sku VARCHAR(100), + description TEXT, + unit_price DECIMAL(20,6) NOT NULL, + currency_code VARCHAR(3) DEFAULT 'USD', + is_active BOOLEAN DEFAULT TRUE NOT NULL, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_product_1 UNIQUE (sku) +); + +--changeset qbit-crm:020-crm_sales_goal +CREATE TABLE IF NOT EXISTS crm_sales_goal ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + user_id TEXT NOT NULL, + pipeline_id INTEGER, + period_type INTEGER NOT NULL, + period_start DATE NOT NULL, + period_end DATE NOT NULL, + target_amount DECIMAL(20,6) NOT NULL, + currency_code VARCHAR(3) DEFAULT 'USD', + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_sales_goal_1 UNIQUE (user_id, pipeline_id, period_type, period_start) +); + +CREATE INDEX IF NOT EXISTS ix_crm_sales_goal_user_id ON crm_sales_goal (user_id); +CREATE INDEX IF NOT EXISTS ix_crm_sales_goal_pipeline_id ON crm_sales_goal (pipeline_id); + +--changeset qbit-crm:020-crm_sequence_enrollment +CREATE TABLE IF NOT EXISTS crm_sequence_enrollment ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + sequence_id INTEGER NOT NULL, + contact_id INTEGER NOT NULL, + deal_id INTEGER, + current_step_number INTEGER DEFAULT 0 NOT NULL, + status INTEGER NOT NULL, + enrolled_date TIMESTAMP WITHOUT TIME ZONE NOT NULL, + enrolled_by_user_id TEXT NOT NULL, + completed_date TIMESTAMP WITHOUT TIME ZONE, + unenrolled_date TIMESTAMP WITHOUT TIME ZONE, + unenroll_reason VARCHAR(250), + next_step_date TIMESTAMP WITHOUT TIME ZONE, + failure_count INTEGER DEFAULT 0, + last_failure_message VARCHAR(1000), + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_sequence_enrollment_1 UNIQUE (sequence_id, contact_id) +); + +CREATE INDEX IF NOT EXISTS ix_crm_sequence_enrollment_sequence_id ON crm_sequence_enrollment (sequence_id); +CREATE INDEX IF NOT EXISTS ix_crm_sequence_enrollment_contact_id ON crm_sequence_enrollment (contact_id); +CREATE INDEX IF NOT EXISTS ix_crm_sequence_enrollment_deal_id ON crm_sequence_enrollment (deal_id); +CREATE INDEX IF NOT EXISTS ix_crm_sequence_enrollment_enrolled_by_user_id ON crm_sequence_enrollment (enrolled_by_user_id); + +--changeset qbit-crm:020-crm_sequence_step +CREATE TABLE IF NOT EXISTS crm_sequence_step ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + sequence_id INTEGER NOT NULL, + step_number INTEGER NOT NULL, + step_type INTEGER NOT NULL, + delay_days INTEGER DEFAULT 0 NOT NULL, + delay_hours INTEGER DEFAULT 0, + email_template_id INTEGER, + task_subject VARCHAR(500), + task_description TEXT, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_sequence_step_1 UNIQUE (sequence_id, step_number) +); + +CREATE INDEX IF NOT EXISTS ix_crm_sequence_step_sequence_id ON crm_sequence_step (sequence_id); +CREATE INDEX IF NOT EXISTS ix_crm_sequence_step_email_template_id ON crm_sequence_step (email_template_id); + +--changeset qbit-crm:020-crm_win_loss_reason +CREATE TABLE IF NOT EXISTS crm_win_loss_reason ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(100) NOT NULL, + type INTEGER NOT NULL, + sort_order INTEGER NOT NULL, + is_active BOOLEAN DEFAULT TRUE NOT NULL, + create_date TIMESTAMP WITHOUT TIME ZONE, + modify_date TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT uq_crm_win_loss_reason_1 UNIQUE (name) +); diff --git a/src/test/java/com/kingsrook/qbits/crm/BaseTest.java b/src/test/java/com/kingsrook/qbits/crm/BaseTest.java index c96bc7b..25f0857 100644 --- a/src/test/java/com/kingsrook/qbits/crm/BaseTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/BaseTest.java @@ -1,18 +1,41 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Base test class for the CRM QBit. Sets up QInstance with all CRM entities ** using MemoryRecordStore and anonymous auth for testing. *******************************************************************************/ + package com.kingsrook.qbits.crm; +import com.kingsrook.qbits.crm.security.CrmPermissions; import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.instances.QInstanceValidator; import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerMultiOutput; import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType; +import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.authentication.QAuthenticationMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; import com.kingsrook.qqq.backend.core.model.session.QSession; import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryBackendModule; import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryRecordStore; @@ -42,7 +65,7 @@ public class BaseTest QInstance qInstance = defineQInstance(); new QInstanceValidator().validate(qInstance); - QSession session = new QSession(); + QSession session = new QSession().withPermissions(CrmPermissions.ALL); session.setIdReference(TEST_USER_ID); QContext.init(qInstance, session); @@ -70,7 +93,7 @@ public class BaseTest { QInstance qInstance = new QInstance(); - qInstance.setAuthentication(new QAuthenticationMetaData() + qInstance.withInstanceDefaultAuthentication(new QAuthenticationMetaData().withName("anonymous") .withType(QAuthenticationType.FULLY_ANONYMOUS)); qInstance.addBackend(new QBackendMetaData() diff --git a/src/test/java/com/kingsrook/qbits/crm/ContingentPossibleValuesTest.java b/src/test/java/com/kingsrook/qbits/crm/ContingentPossibleValuesTest.java index 2cc35a7..eca3426 100644 --- a/src/test/java/com/kingsrook/qbits/crm/ContingentPossibleValuesTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/ContingentPossibleValuesTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Tests for CRM choices scoped by another editable field on the same form. *******************************************************************************/ + package com.kingsrook.qbits.crm; diff --git a/src/test/java/com/kingsrook/qbits/crm/CrmIntegrationTest.java b/src/test/java/com/kingsrook/qbits/crm/CrmIntegrationTest.java index 13fb88e..772ba65 100644 --- a/src/test/java/com/kingsrook/qbits/crm/CrmIntegrationTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/CrmIntegrationTest.java @@ -1,41 +1,52 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** End-to-end integration test for the CRM QBit. Exercises the full lifecycle: ** contacts, companies, form submissions, activities, pipelines, deals, ** deal products, stage changes, audit logs, and stage history. *******************************************************************************/ + package com.kingsrook.qbits.crm; import java.math.BigDecimal; -import java.util.List; import com.kingsrook.qbits.crm.activities.model.Activity; import com.kingsrook.qbits.crm.activities.model.ActivityType; -import com.kingsrook.qbits.crm.audit.model.AuditLog; import com.kingsrook.qbits.crm.core.model.Company; import com.kingsrook.qbits.crm.core.model.Contact; import com.kingsrook.qbits.crm.core.model.FormSubmission; -import com.kingsrook.qbits.crm.core.model.enums.CrmAuditAction; import com.kingsrook.qbits.crm.core.model.enums.CrmDirection; -import com.kingsrook.qbits.crm.core.model.enums.CrmEntityType; import com.kingsrook.qbits.crm.core.model.enums.CrmFormType; import com.kingsrook.qbits.crm.deals.model.Deal; import com.kingsrook.qbits.crm.deals.model.DealProduct; -import com.kingsrook.qbits.crm.deals.model.DealStageHistory; import com.kingsrook.qbits.crm.deals.model.Pipeline; import com.kingsrook.qbits.crm.deals.model.PipelineStage; import com.kingsrook.qbits.crm.deals.model.Product; import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; -import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput; import com.kingsrook.qqq.backend.core.model.data.QRecord; import org.junit.jupiter.api.Test; @@ -236,36 +247,6 @@ class CrmIntegrationTest extends BaseTest assertThat(dealClosedWon.getActualCloseDate()).isNotNull(); assertThat(dealClosedWon.getWeightedAmount()).isEqualByComparingTo(new BigDecimal("10000")); - //////////////////////////////////////////////////////////////////////// - // Step 10: Query AuditLog for CONTACT -> verify CREATED entry // - //////////////////////////////////////////////////////////////////////// - QueryOutput contactAuditQuery = new QueryAction().execute( - new QueryInput(AuditLog.TABLE_NAME) - .withFilter(new QQueryFilter() - .withCriteria(new QFilterCriteria("entityType", QCriteriaOperator.EQUALS, CrmEntityType.CONTACT.getPossibleValueId())))); - List contactAudits = contactAuditQuery.getRecords(); - assertThat(contactAudits).isNotEmpty(); - assertThat(contactAudits).anyMatch(r -> CrmAuditAction.CREATED.getPossibleValueId().equals(r.getValueInteger("action"))); - - //////////////////////////////////////////////////////////////////////// - // Step 11: Query AuditLog for DEAL -> verify CREATED and additional // - //////////////////////////////////////////////////////////////////////// - QueryOutput dealAuditQuery = new QueryAction().execute( - new QueryInput(AuditLog.TABLE_NAME) - .withFilter(new QQueryFilter() - .withCriteria(new QFilterCriteria("entityType", QCriteriaOperator.EQUALS, CrmEntityType.DEAL.getPossibleValueId())))); - List dealAudits = dealAuditQuery.getRecords(); - assertThat(dealAudits).anyMatch(r -> CrmAuditAction.CREATED.getPossibleValueId().equals(r.getValueInteger("action"))); - assertThat(dealAudits.size()).isGreaterThanOrEqualTo(2); - - //////////////////////////////////////////////////////////////////////// - // Step 12: Query DealStageHistory -> verify at least 2 rows // - //////////////////////////////////////////////////////////////////////// - QueryOutput stageHistoryQuery = new QueryAction().execute( - new QueryInput(DealStageHistory.TABLE_NAME) - .withFilter(new QQueryFilter() - .withCriteria(new QFilterCriteria("dealId", QCriteriaOperator.EQUALS, dealId)))); - assertThat(stageHistoryQuery.getRecords().size()).isGreaterThanOrEqualTo(2); } } diff --git a/src/test/java/com/kingsrook/qbits/crm/CrmPermissionsTest.java b/src/test/java/com/kingsrook/qbits/crm/CrmPermissionsTest.java new file mode 100644 index 0000000..b17cb66 --- /dev/null +++ b/src/test/java/com/kingsrook/qbits/crm/CrmPermissionsTest.java @@ -0,0 +1,74 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package com.kingsrook.qbits.crm; + + +import java.util.Set; +import com.kingsrook.qbits.crm.security.CrmPermissions; +import com.kingsrook.qqq.backend.core.actions.permissions.PermissionsHelper; +import com.kingsrook.qqq.backend.core.actions.permissions.TablePermissionSubType; +import com.kingsrook.qqq.backend.core.context.QContext; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; + + +/******************************************************************************* + ** Exercise the core permission checker with ordinary, management and admin grants. + *******************************************************************************/ +class CrmPermissionsTest extends BaseTest +{ + /******************************************************************************* + ** A read grant does not allow writes or settings access. + *******************************************************************************/ + @Test + void testReadOnlyAccess() + { + QContext.getQSession().setPermissions(Set.of(CrmPermissions.READ)); + QueryInput input = new QueryInput("crm_contact"); + assertThat(PermissionsHelper.hasTablePermission(input, "crm_contact", TablePermissionSubType.READ)).isTrue(); + assertThat(PermissionsHelper.hasTablePermission(input, "crm_contact", TablePermissionSubType.EDIT)).isFalse(); + assertThat(PermissionsHelper.hasTablePermission(input, "crm_pipeline", TablePermissionSubType.READ)).isFalse(); + assertThat(PermissionsHelper.hasProcessPermission(input, "crm_gdpr_anonymize_contact")).isFalse(); + assertThat(PermissionsHelper.hasWidgetPermission(input, "crm_activity_feed")).isFalse(); + } + + + + /******************************************************************************* + ** Settings and erasure grants are independent of everyday CRM access. + *******************************************************************************/ + @Test + void testManagementAndAdminAccess() + { + QueryInput input = new QueryInput("crm_contact"); + QContext.getQSession().setPermissions(Set.of(CrmPermissions.APP_ACCESS, CrmPermissions.MANAGE_READ, CrmPermissions.MANAGE_WRITE, CrmPermissions.MANAGE)); + assertThat(PermissionsHelper.hasWidgetPermission(input, "crm_activity_feed")).isTrue(); + assertThat(PermissionsHelper.hasTablePermission(input, "crm_pipeline", TablePermissionSubType.EDIT)).isTrue(); + assertThat(PermissionsHelper.hasProcessPermission(input, "crm_merge_contacts")).isTrue(); + assertThat(PermissionsHelper.hasTablePermission(input, "crm_currency", TablePermissionSubType.READ)).isTrue(); + assertThat(PermissionsHelper.hasProcessPermission(input, "crm_gdpr_anonymize_contact")).isFalse(); + QContext.getQSession().setPermissions(Set.of(CrmPermissions.ADMIN, CrmPermissions.ADMIN_READ, CrmPermissions.ADMIN_WRITE)); + assertThat(PermissionsHelper.hasProcessPermission(input, "crm_gdpr_anonymize_contact")).isTrue(); + } + +} diff --git a/src/test/java/com/kingsrook/qbits/crm/CrmQBitConfigTest.java b/src/test/java/com/kingsrook/qbits/crm/CrmQBitConfigTest.java index ce918e1..b816516 100644 --- a/src/test/java/com/kingsrook/qbits/crm/CrmQBitConfigTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/CrmQBitConfigTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CrmQBitConfig. *******************************************************************************/ + package com.kingsrook.qbits.crm; @@ -9,9 +31,9 @@ import java.util.List; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType; +import com.kingsrook.qqq.backend.core.model.metadata.producers.MetaDataCustomizerInterface; import com.kingsrook.qqq.backend.core.model.metadata.security.RecordSecurityLock; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.producers.MetaDataCustomizerInterface; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -38,22 +60,16 @@ class CrmQBitConfigTest CrmQBitConfig config = new CrmQBitConfig() .withDefaultBackendNameForTables("myBackend") - .withTableNamePrefix("crm_") + .withInferBackendNames(false) .withTableMetaDataCustomizer(customizer) .withSecurityFields(securityFields) - .withRecordSecurityLocks(locks) - .withQuickSearchQBitNamespace("quickSearch") - .withWebhooksQBitNamespace("webhooks") - .withWorkflowsQBitNamespace("workflows"); + .withRecordSecurityLocks(locks); assertThat(config.getDefaultBackendNameForTables()).isEqualTo("myBackend"); - assertThat(config.getTableNamePrefix()).isEqualTo("crm_"); + assertThat(config.getInferBackendNames()).isFalse(); assertThat(config.getTableMetaDataCustomizer()).isSameAs(customizer); assertThat(config.getSecurityFields()).isSameAs(securityFields); assertThat(config.getRecordSecurityLocks()).isSameAs(locks); - assertThat(config.getQuickSearchQBitNamespace()).isEqualTo("quickSearch"); - assertThat(config.getWebhooksQBitNamespace()).isEqualTo("webhooks"); - assertThat(config.getWorkflowsQBitNamespace()).isEqualTo("workflows"); } @@ -117,6 +133,7 @@ class CrmQBitConfigTest void testDefaultConfig() { assertThat(CrmQBitConfig.DEFAULT_CONFIG).isNotNull(); + assertThat(CrmQBitConfig.DEFAULT_CONFIG.getInferBackendNames()).isTrue(); assertThat(CrmQBitConfig.DEFAULT_CONFIG.getDefaultBackendNameForTables()).isNull(); } diff --git a/src/test/java/com/kingsrook/qbits/crm/CrmQBitProducerTest.java b/src/test/java/com/kingsrook/qbits/crm/CrmQBitProducerTest.java index 291d453..f016159 100644 --- a/src/test/java/com/kingsrook/qbits/crm/CrmQBitProducerTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/CrmQBitProducerTest.java @@ -1,11 +1,43 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CrmQBitProducer. *******************************************************************************/ + package com.kingsrook.qbits.crm; +import com.kingsrook.qqq.backend.core.context.QContext; +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerMultiOutput; +import com.kingsrook.qqq.backend.core.model.metadata.audits.AuditLevel; +import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData; import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppSection; +import com.kingsrook.qqq.backend.core.model.metadata.permissions.DenyBehavior; +import com.kingsrook.qqq.backend.core.model.metadata.permissions.PermissionLevel; +import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.qbits.SourceQBitAware; +import com.kingsrook.qqq.backend.module.rdbms.actions.AbstractRDBMSAction; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -82,7 +114,75 @@ class CrmQBitProducerTest extends BaseTest { assertThat(CrmQBitProducer.GROUP_ID).isEqualTo("com.kingsrook.qbits"); assertThat(CrmQBitProducer.ARTIFACT_ID).isEqualTo("crm"); - assertThat(CrmQBitProducer.VERSION).isEqualTo("0.1.0"); + assertThat(CrmQBitProducer.VERSION).isEqualTo("0.2.0-SNAPSHOT"); + } + + /******************************************************************************* + ** Every produced table and field uses the standard backend names. + *******************************************************************************/ + @Test + void testBackendNames() + { + QContext.getQInstance().getTables().values().forEach(table -> + { + assertThat(table.getName()).startsWith("crm_"); + assertThat(AbstractRDBMSAction.getTableName(table)).isEqualTo(table.getName()); + table.getFields().values().forEach(field -> + assertThat(field.getBackendName()).isEqualTo(field.getName().replaceAll("([a-z0-9])([A-Z])", "$1_$2").toLowerCase(java.util.Locale.ROOT))); + }); + } + + /******************************************************************************* + ** Platform audit replaces bespoke tables on the four tracked entities. + *******************************************************************************/ + @Test + void testCoreAuditRules() + { + for(String tableName : java.util.List.of("crm_contact", "crm_company", "crm_deal", "crm_activity")) + { + assertThat(QContext.getQInstance().getTable(tableName).getAuditRules().getAuditLevel()).isEqualTo(AuditLevel.FIELD); + } + assertThat(QContext.getQInstance().getTables()).hasSize(33) + .doesNotContainKeys("crm_tag", "crm_contact_tag", "crm_company_tag", "crm_deal_tag", "crm_attachment", "crm_audit_log"); + assertThat(QContext.getQInstance().getProcesses()).doesNotContainKeys("crm_bulk_add_tag", "crm_bulk_remove_tag"); + } + + /******************************************************************************* + ** All produced metadata is protected and attributed to this QBit. + *******************************************************************************/ + @Test + void testPermissionsAndProvenance() throws QException + { + MetaDataProducerMultiOutput produced = new CrmQBitProducer() + .withQBitConfig(new CrmQBitConfig().withDefaultBackendNameForTables(BACKEND_NAME)) + .produce(new com.kingsrook.qqq.backend.core.model.metadata.QInstance()); + String source = new CrmQBitProducer().getQBitMetaData().getName(); + QContext.getQInstance().getTables().values().forEach(table -> + { + assertThat(table.getName()).matches("crm_[a-z0-9_]+"); + assertThat(table.getSourceQBitName()).isEqualTo(source); + assertThat(table.getPermissionRules()).isNotNull(); + assertThat(table.getPermissionRules().getDenyBehavior()).isEqualTo(DenyBehavior.HIDDEN); + assertThat(table.getPermissionRules().getLevel()).isEqualTo(PermissionLevel.READ_WRITE_PERMISSIONS); + }); + produced.getEach(QProcessMetaData.class).forEach(process -> + { + assertThat(process.getName()).matches("crm_[a-z0-9_]+"); + assertThat(process.getSourceQBitName()).isEqualTo(source); + assertThat(process.getPermissionRules()).isNotNull(); + assertThat(process.getPermissionRules().getDenyBehavior()).isEqualTo(DenyBehavior.HIDDEN); + assertThat(process.getPermissionRules().getLevel()).isEqualTo(PermissionLevel.HAS_ACCESS_PERMISSION); + }); + produced.getEach(QWidgetMetaData.class).forEach(widget -> + { + assertThat(widget.getName()).matches("crm_[a-z0-9_]+"); + assertThat(widget).isInstanceOf(SourceQBitAware.class); + assertThat(((SourceQBitAware) widget).getSourceQBitName()).isEqualTo(source); + assertThat(widget.getPermissionRules()).isNotNull(); + assertThat(widget.getPermissionRules().getDenyBehavior()).isEqualTo(DenyBehavior.HIDDEN); + assertThat(widget.getPermissionRules().getLevel()).isEqualTo(PermissionLevel.HAS_ACCESS_PERMISSION); + }); + QContext.getQInstance().getJoins().values().forEach(join -> assertThat(join.getName()).matches("crm_[a-z0-9_]+")); } } diff --git a/src/test/java/com/kingsrook/qbits/crm/CrmRdbmsTest.java b/src/test/java/com/kingsrook/qbits/crm/CrmRdbmsTest.java new file mode 100644 index 0000000..294791b --- /dev/null +++ b/src/test/java/com/kingsrook/qbits/crm/CrmRdbmsTest.java @@ -0,0 +1,289 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package com.kingsrook.qbits.crm; + + +import java.math.BigDecimal; +import java.nio.file.Files; +import java.nio.file.Path; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import com.kingsrook.qbits.crm.security.CrmPermissions; +import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; +import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; +import com.kingsrook.qqq.backend.core.context.QContext; +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.instances.QInstanceValidator; +import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; +import com.kingsrook.qqq.backend.core.model.data.QRecord; +import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType; +import com.kingsrook.qqq.backend.core.model.metadata.QInstance; +import com.kingsrook.qqq.backend.core.model.metadata.authentication.QAuthenticationMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; +import com.kingsrook.qqq.backend.core.model.session.QSession; +import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager; +import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + + +/******************************************************************************* + ** Real QQQ RDBMS operations over the shipped PostgreSQL DDL, using H2 in + ** PostgreSQL mode. No memory store or replacement SQL schema is involved. + *******************************************************************************/ +class CrmRdbmsTest +{ + private Connection connection; + private QInstance qInstance; + + + + /******************************************************************************* + ** Create the exact reference schema and register the RDBMS-backed QBit. + *******************************************************************************/ + @BeforeEach + void setUp() throws Exception + { + ConnectionManager.resetConnectionProviders(); + String url = "jdbc:h2:mem:crm_" + UUID.randomUUID() + ";MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE;DB_CLOSE_DELAY=-1"; + connection = DriverManager.getConnection(url, "sa", ""); + executeSql(Files.readString(Path.of("docs/ddl/postgres.sql"))); + qInstance = new QInstance(); + qInstance.addBackend(new RDBMSBackendMetaData().withName("rdbms").withVendor("h2") + .withJdbcUrl(url).withUsername("sa").withPassword("")); + qInstance.withInstanceDefaultAuthentication(new QAuthenticationMetaData().withName("anonymous").withType(QAuthenticationType.FULLY_ANONYMOUS)); + qInstance.setEnforcePermissionsInCoreActions(true); + new CrmQBitProducer().withQBitConfig(new CrmQBitConfig().withDefaultBackendNameForTables("rdbms")) + .produce(qInstance).addSelfToInstance(qInstance); + new QInstanceValidator().validate(qInstance); + QContext.init(qInstance, new QSession().withPermissions(CrmPermissions.ALL)); + } + + + + /******************************************************************************* + ** Release the database and request context even when an assertion fails. + *******************************************************************************/ + @AfterEach + void tearDown() throws Exception + { + QContext.clear(); + ConnectionManager.resetConnectionProviders(); + if(connection != null) + { + try(Statement statement = connection.createStatement()) + { + statement.execute("SHUTDOWN"); + } + finally + { + connection.close(); + } + } + } + + + + /******************************************************************************* + ** Persist the seven required entity types through QQQ, including customizers. + *******************************************************************************/ + @Test + void testPersistAndQueryCrmRecords() throws Exception + { + Integer company = insert("crm_company", new QRecord().withValue("name", "Example Company").withValue("ownerUserId", "rep")); + Integer contact = insert("crm_contact", new QRecord().withValue("firstName", "Ada").withValue("lastName", "Lovelace") + .withValue("email", "ada@example.test").withValue("ownerUserId", "rep").withValue("companyId", company)); + Integer pipeline = insert("crm_pipeline", new QRecord().withValue("name", "Sales")); + Integer stage = insert("crm_pipeline_stage", new QRecord().withValue("name", "Qualified").withValue("pipelineId", pipeline) + .withValue("sortOrder", 1).withValue("probabilityPct", 20)); + Integer deal = insert("crm_deal", new QRecord().withValue("name", "First sale").withValue("ownerUserId", "rep") + .withValue("companyId", company).withValue("primaryContactId", contact).withValue("pipelineId", pipeline) + .withValue("pipelineStageId", stage).withValue("amount", new BigDecimal("123.45"))); + Integer activityType = insert("crm_activity_type", new QRecord().withValue("name", "Call").withValue("sortOrder", 1)); + Integer activity = insert("crm_activity", new QRecord().withValue("activityTypeId", activityType).withValue("subject", "Discovery call") + .withValue("ownerUserId", "rep").withValue("contactId", contact).withValue("companyId", company).withValue("dealId", deal)); + Integer submission = insert("crm_form_submission", new QRecord().withValue("formType", 1).withValue("email", "ada@example.test") + .withValue("firstName", "Ada").withValue("lastName", "Lovelace")); + Integer list = insert("crm_email_list", new QRecord().withValue("name", "Newsletter").withValue("slug", "newsletter").withValue("sortOrder", 1)); + Integer member = insert("crm_email_list_member", new QRecord().withValue("emailListId", list).withValue("contactId", contact) + .withValue("email", "ada@example.test").withValue("subscribedDate", Instant.parse("2026-10-14T12:00:00Z")).withValue("formSubmissionId", submission)); + Integer consent = insert("crm_consent_record", new QRecord().withValue("contactId", contact).withValue("consentType", 1) + .withValue("status", 1).withValue("consentDate", Instant.parse("2026-10-14T12:00:00Z")).withValue("source", "RDBMS test")); + + assertThat(query("crm_company", company).getValueString("name")).isEqualTo("Example Company"); + assertThat(query("crm_contact", contact).getValueInteger("companyId")).isEqualTo(company); + assertThat(query("crm_deal", deal).getValueBigDecimal("amount")).isEqualByComparingTo("123.45"); + assertThat(query("crm_deal", deal).getValueBigDecimal("weightedAmount")).isEqualByComparingTo("24.69"); + assertThat(query("crm_activity", activity).getValueInteger("dealId")).isEqualTo(deal); + assertThat(query("crm_form_submission", submission).getValueInteger("contactId")).isEqualTo(contact); + assertThat(query("crm_email_list_member", member).getValueInteger("formSubmissionId")).isEqualTo(submission); + assertThat(query("crm_consent_record", consent).getValueString("source")).isEqualTo("RDBMS test"); + + try(Statement statement = connection.createStatement()) + { + SQLException duplicate = assertThrows(SQLException.class, () -> statement.executeUpdate( + "INSERT INTO crm_email_list_member (email_list_id, email, status, subscribed_date) " + + "SELECT email_list_id, email, status, subscribed_date FROM crm_email_list_member WHERE id = " + member)); + assertThat(duplicate.getSQLState()).isEqualTo("23505"); + } + } + + + + /******************************************************************************* + ** All 395 columns, metadata unique keys and relationship indexes exist in SQL. + *******************************************************************************/ + @Test + void testSchemaMatchesMetadata() throws Exception + { + assertThat(qInstance.getTables()).hasSize(33); + for(QTableMetaData table : qInstance.getTables().values()) + { + Set columns = new HashSet<>(); + try(ResultSet result = connection.getMetaData().getColumns(null, "public", table.getName(), null)) + { + while(result.next()) + { + columns.add(result.getString("COLUMN_NAME")); + } + } + assertThat(columns).as(table.getName()).containsExactlyInAnyOrderElementsOf( + table.getFields().values().stream().map(field -> field.getBackendName()).toList()); + Map> uniqueIndexes = new HashMap<>(); + Set indexedColumns = new HashSet<>(); + try(ResultSet result = connection.getMetaData().getIndexInfo(null, "public", table.getName(), false, false)) + { + while(result.next()) + { + String column = result.getString("COLUMN_NAME"); + indexedColumns.add(column); + if(!result.getBoolean("NON_UNIQUE")) + { + uniqueIndexes.computeIfAbsent(result.getString("INDEX_NAME"), key -> new ArrayList<>()).add(column); + } + } + } + if(table.getUniqueKeys() != null) + { + for(UniqueKey key : table.getUniqueKeys()) + { + List expected = key.getFieldNames().stream().map(field -> table.getField(field).getBackendName()).toList(); + assertThat(uniqueIndexes.values()).as(table.getName() + " unique key " + expected).contains(expected); + } + } + table.getFields().values().stream().filter(field -> field.getName().endsWith("Id")).forEach(field -> + assertThat(indexedColumns).as(table.getName() + "." + field.getName()).contains(field.getBackendName())); + assertThat(new QueryAction().execute(new QueryInput(table.getName())).getRecords()).isEmpty(); + } + } + + + + /******************************************************************************* + ** Both install paths contain identical SQL, with one Liquibase changeset per table. + *******************************************************************************/ + @Test + void testLiquibaseMatchesReferenceDdl() throws Exception + { + String ddl = Files.readString(Path.of("docs/ddl/postgres.sql")); + String changelog = Files.readString(Path.of("src/main/resources/db/liquibase/qbit-crm/crm.changelog.sql")); + assertThat(changelog).startsWith("--liquibase formatted sql"); + assertThat(changelog.lines().filter(line -> line.startsWith("--changeset qbit-crm:")).count()).isEqualTo(33); + assertThat(stripComments(changelog)).isEqualTo(stripComments(ddl)); + } + + + + /******************************************************************************* + ** Insert through QQQ and fail on record-level validation errors. + *******************************************************************************/ + private Integer insert(String table, QRecord record) throws QException + { + QRecord inserted = new InsertAction().execute(new InsertInput(table).withRecord(record)).getRecords().get(0); + assertThat(inserted.getErrors()).isNullOrEmpty(); + assertThat(inserted.getValueInteger("id")).isNotNull(); + return (inserted.getValueInteger("id")); + } + + + + /******************************************************************************* + ** Query by id through the real backend, verifying one persisted record. + *******************************************************************************/ + private QRecord query(String table, Integer id) throws QException + { + List records = new QueryAction().execute(new QueryInput(table) + .withFilter(new QQueryFilter(new QFilterCriteria("id", QCriteriaOperator.EQUALS, id)))).getRecords(); + assertThat(records).hasSize(1); + return (records.get(0)); + } + + + + /******************************************************************************* + ** Run the simple formatted SQL statements used by this schema. + *******************************************************************************/ + private void executeSql(String sql) throws SQLException + { + try(Statement statement = connection.createStatement()) + { + for(String part : stripComments(sql).split(";")) + { + if(!part.isBlank()) + { + statement.execute(part); + } + } + } + } + + + + /******************************************************************************* + ** Normalize SQL independently of descriptive or Liquibase comment lines. + *******************************************************************************/ + private String stripComments(String sql) + { + return (sql.lines().filter(line -> !line.stripLeading().startsWith("--")).filter(line -> !line.isBlank()) + .collect(java.util.stream.Collectors.joining("\n"))); + } + +} diff --git a/src/test/java/com/kingsrook/qbits/crm/activities/ActivityParticipantTest.java b/src/test/java/com/kingsrook/qbits/crm/activities/ActivityParticipantTest.java index b03d7c3..f7193c4 100644 --- a/src/test/java/com/kingsrook/qbits/crm/activities/ActivityParticipantTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/activities/ActivityParticipantTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for the ActivityParticipant entity. *******************************************************************************/ + package com.kingsrook.qbits.crm.activities; @@ -19,7 +41,6 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; import com.kingsrook.qqq.backend.core.model.data.QRecord; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; diff --git a/src/test/java/com/kingsrook/qbits/crm/activities/ActivityTest.java b/src/test/java/com/kingsrook/qbits/crm/activities/ActivityTest.java index 8b6368d..add2ff0 100644 --- a/src/test/java/com/kingsrook/qbits/crm/activities/ActivityTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/activities/ActivityTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for the Activity entity. *******************************************************************************/ + package com.kingsrook.qbits.crm.activities; @@ -21,7 +43,6 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; import com.kingsrook.qqq.backend.core.model.data.QRecord; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; diff --git a/src/test/java/com/kingsrook/qbits/crm/activities/ActivityTypeTest.java b/src/test/java/com/kingsrook/qbits/crm/activities/ActivityTypeTest.java index f08b244..734efd0 100644 --- a/src/test/java/com/kingsrook/qbits/crm/activities/ActivityTypeTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/activities/ActivityTypeTest.java @@ -1,25 +1,43 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for the ActivityType entity. *******************************************************************************/ + package com.kingsrook.qbits.crm.activities; -import java.util.List; import com.kingsrook.qbits.crm.BaseTest; import com.kingsrook.qbits.crm.activities.model.ActivityType; -import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; import com.kingsrook.qqq.backend.core.model.data.QRecord; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; diff --git a/src/test/java/com/kingsrook/qbits/crm/activities/customizers/ActivityLastDateCustomizerTest.java b/src/test/java/com/kingsrook/qbits/crm/activities/customizers/ActivityLastDateCustomizerTest.java index 76bfd88..e15d553 100644 --- a/src/test/java/com/kingsrook/qbits/crm/activities/customizers/ActivityLastDateCustomizerTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/activities/customizers/ActivityLastDateCustomizerTest.java @@ -1,14 +1,34 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for ActivityLastDateCustomizer -- verifies that inserting an ** Activity updates lastActivityDate and lastContactedDate on linked ** Contact, Company, and Deal records. *******************************************************************************/ + package com.kingsrook.qbits.crm.activities.customizers; import java.math.BigDecimal; -import java.time.Instant; -import java.time.temporal.ChronoUnit; import com.kingsrook.qbits.crm.BaseTest; import com.kingsrook.qbits.crm.activities.model.Activity; import com.kingsrook.qbits.crm.activities.model.ActivityType; @@ -23,7 +43,6 @@ import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; -import com.kingsrook.qqq.backend.core.model.data.QRecord; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; diff --git a/src/test/java/com/kingsrook/qbits/crm/activities/processes/FireRemindersProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/activities/processes/FireRemindersProcessTest.java index c212a85..1070125 100644 --- a/src/test/java/com/kingsrook/qbits/crm/activities/processes/FireRemindersProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/activities/processes/FireRemindersProcessTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for FireRemindersProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.activities.processes; diff --git a/src/test/java/com/kingsrook/qbits/crm/activities/processes/LogActivityProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/activities/processes/LogActivityProcessTest.java index 7bb3054..281fbc3 100644 --- a/src/test/java/com/kingsrook/qbits/crm/activities/processes/LogActivityProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/activities/processes/LogActivityProcessTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for LogActivityProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.activities.processes; diff --git a/src/test/java/com/kingsrook/qbits/crm/activities/processes/ProcessOverdueTasksProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/activities/processes/ProcessOverdueTasksProcessTest.java index c508ade..0d67c2c 100644 --- a/src/test/java/com/kingsrook/qbits/crm/activities/processes/ProcessOverdueTasksProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/activities/processes/ProcessOverdueTasksProcessTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for ProcessOverdueTasksProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.activities.processes; diff --git a/src/test/java/com/kingsrook/qbits/crm/audit/AuditLogTest.java b/src/test/java/com/kingsrook/qbits/crm/audit/AuditLogTest.java deleted file mode 100644 index 2036749..0000000 --- a/src/test/java/com/kingsrook/qbits/crm/audit/AuditLogTest.java +++ /dev/null @@ -1,129 +0,0 @@ -/******************************************************************************* - ** Tests for AuditLog entity -- validates insert succeeds and that update/delete - ** are blocked by the immutability customizers. - *******************************************************************************/ -package com.kingsrook.qbits.crm.audit; - - -import java.util.List; -import com.kingsrook.qbits.crm.BaseTest; -import com.kingsrook.qbits.crm.audit.model.AuditLog; -import com.kingsrook.qbits.crm.core.model.enums.CrmAuditAction; -import com.kingsrook.qbits.crm.core.model.enums.CrmEntityType; -import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction; -import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; -import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; -import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; -import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; -import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput; -import com.kingsrook.qqq.backend.core.model.data.QRecord; -import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - - -/******************************************************************************* - ** Tests for the AuditLog entity and its immutability customizers. - *******************************************************************************/ -class AuditLogTest extends BaseTest -{ - - /******************************************************************************* - ** Verify that audit log records can be inserted successfully. - *******************************************************************************/ - @Test - void testInsertAuditLog() throws Exception - { - InsertInput insertInput = new InsertInput(); - insertInput.setTableName(AuditLog.TABLE_NAME); - insertInput.setRecords(List.of(new QRecord() - .withValue("entityType", CrmEntityType.CONTACT.getId()) - .withValue("entityId", 42) - .withValue("action", CrmAuditAction.CREATED.getId()) - .withValue("userId", "testUser") - .withValue("message", "Contact created"))); - - InsertOutput insertOutput = new InsertAction().execute(insertInput); - - assertThat(insertOutput.getRecords()).hasSize(1); - QRecord inserted = insertOutput.getRecords().get(0); - assertThat(inserted.getValue("id")).isNotNull(); - assertThat(inserted.getValueInteger("entityId")).isEqualTo(42); - assertThat(inserted.getValueInteger("action")).isEqualTo(CrmAuditAction.CREATED.getId()); - assertThat(inserted.getValueString("userId")).isEqualTo("testUser"); - assertThat(inserted.getValueString("message")).isEqualTo("Contact created"); - } - - - - /******************************************************************************* - ** Verify that updating an audit log record throws QUserFacingException. - *******************************************************************************/ - @Test - void testUpdateAuditLogThrows() throws Exception - { - ///////////////////////////// - // insert a record first // - ///////////////////////////// - InsertInput insertInput = new InsertInput(); - insertInput.setTableName(AuditLog.TABLE_NAME); - insertInput.setRecords(List.of(new QRecord() - .withValue("entityType", CrmEntityType.CONTACT.getId()) - .withValue("entityId", 1) - .withValue("action", CrmAuditAction.CREATED.getId()) - .withValue("userId", "testUser"))); - - InsertOutput insertOutput = new InsertAction().execute(insertInput); - Integer id = insertOutput.getRecords().get(0).getValueInteger("id"); - - ///////////////////////////// - // attempt to update it // - ///////////////////////////// - UpdateInput updateInput = new UpdateInput(); - updateInput.setTableName(AuditLog.TABLE_NAME); - updateInput.setRecords(List.of(new QRecord() - .withValue("id", id) - .withValue("message", "This should fail"))); - - assertThatThrownBy(() -> new UpdateAction().execute(updateInput)) - .isInstanceOf(QUserFacingException.class) - .hasMessageContaining("Audit log records cannot be modified or deleted"); - } - - - - /******************************************************************************* - ** Verify that deleting an audit log record throws QUserFacingException. - *******************************************************************************/ - @Test - void testDeleteAuditLogThrows() throws Exception - { - ///////////////////////////// - // insert a record first // - ///////////////////////////// - InsertInput insertInput = new InsertInput(); - insertInput.setTableName(AuditLog.TABLE_NAME); - insertInput.setRecords(List.of(new QRecord() - .withValue("entityType", CrmEntityType.COMPANY.getId()) - .withValue("entityId", 99) - .withValue("action", CrmAuditAction.DELETED.getId()) - .withValue("userId", "testUser"))); - - InsertOutput insertOutput = new InsertAction().execute(insertInput); - Integer id = insertOutput.getRecords().get(0).getValueInteger("id"); - - ///////////////////////////// - // attempt to delete it // - ///////////////////////////// - DeleteInput deleteInput = new DeleteInput(); - deleteInput.setTableName(AuditLog.TABLE_NAME); - deleteInput.setPrimaryKeys(List.of(id)); - - assertThatThrownBy(() -> new DeleteAction().execute(deleteInput)) - .isInstanceOf(QUserFacingException.class) - .hasMessageContaining("Audit log records cannot be modified or deleted"); - } - -} diff --git a/src/test/java/com/kingsrook/qbits/crm/audit/CrmAuditLogCustomizerTest.java b/src/test/java/com/kingsrook/qbits/crm/audit/CrmAuditLogCustomizerTest.java deleted file mode 100644 index dfe0751..0000000 --- a/src/test/java/com/kingsrook/qbits/crm/audit/CrmAuditLogCustomizerTest.java +++ /dev/null @@ -1,251 +0,0 @@ -/******************************************************************************* - ** Tests for CrmAuditLogCustomizer -- validates audit log entry creation - ** for insert, update, and delete operations on tracked entities. - ** - ** Since Contact/Company entities may not yet be registered with full - ** customizers, these tests exercise the customizer directly by calling its - ** methods with constructed QRecords and verifying audit log entries are - ** created in the crm_audit_log table. - *******************************************************************************/ -package com.kingsrook.qbits.crm.audit; - - -import java.util.List; -import java.util.Optional; -import com.kingsrook.qbits.crm.BaseTest; -import com.kingsrook.qbits.crm.audit.customizers.CrmAuditLogCustomizer; -import com.kingsrook.qbits.crm.audit.model.AuditLog; -import com.kingsrook.qbits.crm.core.model.enums.CrmAuditAction; -import com.kingsrook.qbits.crm.core.model.enums.CrmEntityType; -import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; -import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; -import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput; -import com.kingsrook.qqq.backend.core.model.data.QRecord; -import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; - - -/******************************************************************************* - ** Tests for CrmAuditLogCustomizer. Exercises the customizer directly by - ** invoking postInsert, postUpdate, and postDelete with mock data, then - ** verifying that audit log records were created in the memory backend. - *******************************************************************************/ -class CrmAuditLogCustomizerTest extends BaseTest -{ - - /******************************************************************************* - ** Test that postInsert creates a CREATED audit log entry. - *******************************************************************************/ - @Test - void testPostInsertCreatesAuditEntry() throws Exception - { - CrmAuditLogCustomizer customizer = new CrmAuditLogCustomizer(); - - ////////////////////////////////////////// - // simulate a record that was inserted // - ////////////////////////////////////////// - QRecord insertedRecord = new QRecord() - .withValue("id", 1) - .withValue("name", "Test Contact"); - - InsertInput insertInput = new InsertInput(); - insertInput.setTableName("crmContact"); - - customizer.postInsert(insertInput, List.of(insertedRecord)); - - ////////////////////////////////////////////// - // verify the audit log entry was created // - ////////////////////////////////////////////// - List auditRecords = queryAllAuditLogs(); - assertThat(auditRecords).hasSize(1); - - QRecord auditEntry = auditRecords.get(0); - assertThat(auditEntry.getValueInteger("entityType")).isEqualTo(CrmEntityType.CONTACT.getId()); - assertThat(auditEntry.getValueInteger("entityId")).isEqualTo(1); - assertThat(auditEntry.getValueInteger("action")).isEqualTo(CrmAuditAction.CREATED.getId()); - assertThat(auditEntry.getValueString("message")).isEqualTo("Record created"); - } - - - - /******************************************************************************* - ** Test that postUpdate creates UPDATED entries for changed fields. - ** Uses AuditLog.TABLE_NAME as the table so that getTable() resolves. - *******************************************************************************/ - @Test - void testPostUpdateCreatesAuditEntries() throws Exception - { - CrmAuditLogCustomizer customizer = new CrmAuditLogCustomizer(); - - ////////////////////////////////////////// - // build old and new records // - ////////////////////////////////////////// - QRecord oldRecord = new QRecord() - .withValue("id", 10) - .withValue("message", "Old message") - .withValue("userId", "sameUser"); - - QRecord newRecord = new QRecord() - .withValue("id", 10) - .withValue("message", "New message") - .withValue("userId", "sameUser"); - - UpdateInput updateInput = new UpdateInput(); - updateInput.setTableName(AuditLog.TABLE_NAME); - - customizer.postUpdate(updateInput, List.of(newRecord), Optional.of(List.of(oldRecord))); - - ////////////////////////////////////////////// - // verify audit log entries were created // - ////////////////////////////////////////////// - List auditRecords = queryAllAuditLogs(); - - ///////////////////////////////////////////////////////////////////// - // should have one entry for the "message" field that changed // - // "userId" did not change so it should not have an audit entry // - ///////////////////////////////////////////////////////////////////// - assertThat(auditRecords).hasSize(1); - - QRecord auditEntry = auditRecords.get(0); - assertThat(auditEntry.getValueString("fieldName")).isEqualTo("message"); - assertThat(auditEntry.getValueString("oldValue")).isEqualTo("Old message"); - assertThat(auditEntry.getValueString("newValue")).isEqualTo("New message"); - assertThat(auditEntry.getValueInteger("action")).isEqualTo(CrmAuditAction.UPDATED.getId()); - assertThat(auditEntry.getValueInteger("entityId")).isEqualTo(10); - } - - - - /******************************************************************************* - ** Test that postUpdate detects OWNER_CHANGED for ownerUserId field changes. - ** Uses AuditLog.TABLE_NAME as the table so that getTable() resolves. - *******************************************************************************/ - @Test - void testPostUpdateDetectsOwnerChange() throws Exception - { - CrmAuditLogCustomizer customizer = new CrmAuditLogCustomizer(); - - QRecord oldRecord = new QRecord() - .withValue("id", 20) - .withValue("ownerUserId", "userA"); - - QRecord newRecord = new QRecord() - .withValue("id", 20) - .withValue("ownerUserId", "userB"); - - UpdateInput updateInput = new UpdateInput(); - updateInput.setTableName(AuditLog.TABLE_NAME); - - customizer.postUpdate(updateInput, List.of(newRecord), Optional.of(List.of(oldRecord))); - - List auditRecords = queryAllAuditLogs(); - assertThat(auditRecords).hasSize(1); - assertThat(auditRecords.get(0).getValueInteger("action")).isEqualTo(CrmAuditAction.OWNER_CHANGED.getId()); - assertThat(auditRecords.get(0).getValueString("fieldName")).isEqualTo("ownerUserId"); - } - - - - /******************************************************************************* - ** Test that postUpdate detects STAGE_CHANGED for pipelineStageId field changes. - ** Uses AuditLog.TABLE_NAME as the table so that getTable() resolves. - *******************************************************************************/ - @Test - void testPostUpdateDetectsStageChange() throws Exception - { - CrmAuditLogCustomizer customizer = new CrmAuditLogCustomizer(); - - QRecord oldRecord = new QRecord() - .withValue("id", 30) - .withValue("pipelineStageId", 1); - - QRecord newRecord = new QRecord() - .withValue("id", 30) - .withValue("pipelineStageId", 2); - - UpdateInput updateInput = new UpdateInput(); - updateInput.setTableName(AuditLog.TABLE_NAME); - - customizer.postUpdate(updateInput, List.of(newRecord), Optional.of(List.of(oldRecord))); - - List auditRecords = queryAllAuditLogs(); - assertThat(auditRecords).hasSize(1); - assertThat(auditRecords.get(0).getValueInteger("action")).isEqualTo(CrmAuditAction.STAGE_CHANGED.getId()); - assertThat(auditRecords.get(0).getValueString("fieldName")).isEqualTo("pipelineStageId"); - } - - - - /******************************************************************************* - ** Test that postDelete creates a DELETED audit log entry. - *******************************************************************************/ - @Test - void testPostDeleteCreatesAuditEntry() throws Exception - { - CrmAuditLogCustomizer customizer = new CrmAuditLogCustomizer(); - - QRecord deletedRecord = new QRecord() - .withValue("id", 50); - - DeleteInput deleteInput = new DeleteInput(); - deleteInput.setTableName("crmCompany"); - - customizer.postDelete(deleteInput, List.of(deletedRecord)); - - List auditRecords = queryAllAuditLogs(); - assertThat(auditRecords).hasSize(1); - - QRecord auditEntry = auditRecords.get(0); - assertThat(auditEntry.getValueInteger("entityType")).isEqualTo(CrmEntityType.COMPANY.getId()); - assertThat(auditEntry.getValueInteger("entityId")).isEqualTo(50); - assertThat(auditEntry.getValueInteger("action")).isEqualTo(CrmAuditAction.DELETED.getId()); - assertThat(auditEntry.getValueString("message")).isEqualTo("Record deleted"); - } - - - - /******************************************************************************* - ** Test that records with errors are skipped during audit logging. - *******************************************************************************/ - @Test - void testRecordsWithErrorsAreSkipped() throws Exception - { - CrmAuditLogCustomizer customizer = new CrmAuditLogCustomizer(); - - QRecord goodRecord = new QRecord() - .withValue("id", 1); - - QRecord badRecord = new QRecord() - .withValue("id", 2); - badRecord.addError(new com.kingsrook.qqq.backend.core.model.statusmessages.BadInputStatusMessage("test error")); - - InsertInput insertInput = new InsertInput(); - insertInput.setTableName("crmDeal"); - - customizer.postInsert(insertInput, List.of(goodRecord, badRecord)); - - List auditRecords = queryAllAuditLogs(); - assertThat(auditRecords).hasSize(1); - assertThat(auditRecords.get(0).getValueInteger("entityId")).isEqualTo(1); - } - - - - /******************************************************************************* - ** Helper to query all records from the audit log table. - *******************************************************************************/ - private List queryAllAuditLogs() throws Exception - { - QueryInput queryInput = new QueryInput(); - queryInput.setTableName(AuditLog.TABLE_NAME); - queryInput.setFilter(new QQueryFilter()); - - QueryOutput queryOutput = new QueryAction().execute(queryInput); - return (queryOutput.getRecords()); - } - -} diff --git a/src/test/java/com/kingsrook/qbits/crm/core/customizers/FormSubmissionAutoLinkCustomizerTest.java b/src/test/java/com/kingsrook/qbits/crm/core/customizers/FormSubmissionAutoLinkCustomizerTest.java index 874736b..852911a 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/customizers/FormSubmissionAutoLinkCustomizerTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/customizers/FormSubmissionAutoLinkCustomizerTest.java @@ -1,7 +1,29 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for FormSubmissionAutoLinkCustomizer -- verifies that inserting a ** FormSubmission auto-links contactId when a matching contact email exists. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.customizers; diff --git a/src/test/java/com/kingsrook/qbits/crm/core/model/CompanyCoverageTest.java b/src/test/java/com/kingsrook/qbits/crm/core/model/CompanyCoverageTest.java index aacbcdd..ef871d2 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/model/CompanyCoverageTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/model/CompanyCoverageTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Coverage tests for Company entity -- exercises every getter/setter/withX. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; diff --git a/src/test/java/com/kingsrook/qbits/crm/core/model/CompanyTest.java b/src/test/java/com/kingsrook/qbits/crm/core/model/CompanyTest.java index bb4e37b..bb7664c 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/model/CompanyTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/model/CompanyTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit test for Company entity *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; diff --git a/src/test/java/com/kingsrook/qbits/crm/core/model/ContactChildTableTest.java b/src/test/java/com/kingsrook/qbits/crm/core/model/ContactChildTableTest.java index bf6f18b..a414ff4 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/model/ContactChildTableTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/model/ContactChildTableTest.java @@ -1,7 +1,29 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests verifying Contact child table joins for Activity, DealContact, - ** ContactTag, and ConsentRecord. + ** and ConsentRecord. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; @@ -28,14 +50,13 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; /******************************************************************************* ** Tests that Contact entity has child joins for Activity, DealContact, - ** ContactTag, and ConsentRecord, and that child records can be inserted + ** and ConsentRecord, and that child records can be inserted ** and queried against a parent contact. *******************************************************************************/ class ContactChildTableTest extends BaseTest @@ -47,7 +68,7 @@ class ContactChildTableTest extends BaseTest @Test void testContactActivityJoinExists() { - String joinName = QJoinMetaData.makeInferredJoinName(Contact.TABLE_NAME, Activity.TABLE_NAME); + String joinName = QJoinMetaData.makeInferredJoinName(Contact.TABLE_NAME, Activity.TABLE_NAME).replaceAll("([a-z0-9])([A-Z])", "$1_$2").toLowerCase(java.util.Locale.ROOT); QJoinMetaData join = QContext.getQInstance().getJoin(joinName); assertNotNull(join, "Expected join from Contact to Activity to exist"); } @@ -60,33 +81,20 @@ class ContactChildTableTest extends BaseTest @Test void testContactDealContactJoinExists() { - String joinName = QJoinMetaData.makeInferredJoinName(Contact.TABLE_NAME, DealContact.TABLE_NAME); + String joinName = QJoinMetaData.makeInferredJoinName(Contact.TABLE_NAME, DealContact.TABLE_NAME).replaceAll("([a-z0-9])([A-Z])", "$1_$2").toLowerCase(java.util.Locale.ROOT); QJoinMetaData join = QContext.getQInstance().getJoin(joinName); assertNotNull(join, "Expected join from Contact to DealContact to exist"); } - /******************************************************************************* - ** Verify the join from Contact to ContactTag exists in the QInstance. - *******************************************************************************/ - @Test - void testContactContactTagJoinExists() - { - String joinName = QJoinMetaData.makeInferredJoinName(Contact.TABLE_NAME, ContactTag.TABLE_NAME); - QJoinMetaData join = QContext.getQInstance().getJoin(joinName); - assertNotNull(join, "Expected join from Contact to ContactTag to exist"); - } - - - /******************************************************************************* ** Verify the join from Contact to ConsentRecord exists in the QInstance. *******************************************************************************/ @Test void testContactConsentRecordJoinExists() { - String joinName = QJoinMetaData.makeInferredJoinName(Contact.TABLE_NAME, ConsentRecord.TABLE_NAME); + String joinName = QJoinMetaData.makeInferredJoinName(Contact.TABLE_NAME, ConsentRecord.TABLE_NAME).replaceAll("([a-z0-9])([A-Z])", "$1_$2").toLowerCase(java.util.Locale.ROOT); QJoinMetaData join = QContext.getQInstance().getJoin(joinName); assertNotNull(join, "Expected join from Contact to ConsentRecord to exist"); } @@ -94,7 +102,7 @@ class ContactChildTableTest extends BaseTest /******************************************************************************* - ** Insert a contact, then insert child Activity, DealContact, ContactTag, + ** Insert a contact, then insert child Activity, DealContact, ** and ConsentRecord records referencing it. Verify all persist and can be ** queried by contactId. *******************************************************************************/ @@ -138,19 +146,6 @@ class ContactChildTableTest extends BaseTest .withFilter(new QQueryFilter(new QFilterCriteria("contactId", QCriteriaOperator.EQUALS, contactId)))); assertEquals(1, dealContactQuery.getRecords().size()); - /////////////////////////// - // insert a contact tag // - /////////////////////////// - Integer tagId = insertTag("VIP"); - new InsertAction().execute(new InsertInput(ContactTag.TABLE_NAME) - .withRecordEntity(new ContactTag() - .withContactId(contactId) - .withTagId(tagId))); - - QueryOutput tagQuery = new QueryAction().execute(new QueryInput(ContactTag.TABLE_NAME) - .withFilter(new QQueryFilter(new QFilterCriteria("contactId", QCriteriaOperator.EQUALS, contactId)))); - assertEquals(1, tagQuery.getRecords().size()); - //////////////////////////////// // insert a consent record // //////////////////////////////// @@ -253,16 +248,4 @@ class ContactChildTableTest extends BaseTest - /*************************************************************************** - ** Helper: insert a Tag and return its id. - ***************************************************************************/ - private Integer insertTag(String name) throws QException - { - InsertOutput output = new InsertAction().execute( - new InsertInput(Tag.TABLE_NAME) - .withRecordEntity(new Tag() - .withName(name))); - return (output.getRecords().get(0).getValueInteger("id")); - } - } diff --git a/src/test/java/com/kingsrook/qbits/crm/core/model/ContactCoverageTest.java b/src/test/java/com/kingsrook/qbits/crm/core/model/ContactCoverageTest.java index ac5df6c..09679a3 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/model/ContactCoverageTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/model/ContactCoverageTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Coverage tests for Contact entity -- exercises every getter/setter/withX. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; diff --git a/src/test/java/com/kingsrook/qbits/crm/core/model/ContactTest.java b/src/test/java/com/kingsrook/qbits/crm/core/model/ContactTest.java index 014d087..c70400e 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/model/ContactTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/model/ContactTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit test for Contact entity *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; diff --git a/src/test/java/com/kingsrook/qbits/crm/core/model/CurrencyTest.java b/src/test/java/com/kingsrook/qbits/crm/core/model/CurrencyTest.java index 3bc12b6..b5ce891 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/model/CurrencyTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/model/CurrencyTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit test for Currency entity *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; diff --git a/src/test/java/com/kingsrook/qbits/crm/core/model/EmailListTest.java b/src/test/java/com/kingsrook/qbits/crm/core/model/EmailListTest.java index c38ecd7..c80edc9 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/model/EmailListTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/model/EmailListTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit test for EmailList and EmailListMember entities *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; diff --git a/src/test/java/com/kingsrook/qbits/crm/core/model/FormSubmissionCoverageTest.java b/src/test/java/com/kingsrook/qbits/crm/core/model/FormSubmissionCoverageTest.java index 9433825..9f09b36 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/model/FormSubmissionCoverageTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/model/FormSubmissionCoverageTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Coverage tests for FormSubmission entity -- exercises every getter/setter/withX. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; diff --git a/src/test/java/com/kingsrook/qbits/crm/core/model/FormSubmissionTest.java b/src/test/java/com/kingsrook/qbits/crm/core/model/FormSubmissionTest.java index 8b46632..2142476 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/model/FormSubmissionTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/model/FormSubmissionTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit test for FormSubmission entity *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; diff --git a/src/test/java/com/kingsrook/qbits/crm/core/model/LifecycleStageTest.java b/src/test/java/com/kingsrook/qbits/crm/core/model/LifecycleStageTest.java index 5a56b0a..aeabcd9 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/model/LifecycleStageTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/model/LifecycleStageTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit test for LifecycleStage entity *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model; diff --git a/src/test/java/com/kingsrook/qbits/crm/core/model/enums/CrmEnumPvsTest.java b/src/test/java/com/kingsrook/qbits/crm/core/model/enums/CrmEnumPvsTest.java index 452bdaa..664be2d 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/model/enums/CrmEnumPvsTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/model/enums/CrmEnumPvsTest.java @@ -1,8 +1,30 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Test class for all CRM PossibleValueSource enums. Validates NAME constants, ** getById() lookups, null/unknown ID handling, and PossibleValueEnum interface ** contract for every enum value across all 24 CRM enums. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.model.enums; @@ -468,39 +490,6 @@ class CrmEnumPvsTest - /******************************************************************************* - ** Test CrmAuditAction - *******************************************************************************/ - @Test - void testCrmAuditAction() - { - assertThat(CrmAuditAction.NAME).isNotNull(); - assertThat(CrmAuditAction.getById(null)).isNull(); - assertThat(CrmAuditAction.getById(999)).isNull(); - - assertEnumValue(CrmAuditAction.CREATED, 1, "Created"); - assertEnumValue(CrmAuditAction.UPDATED, 2, "Updated"); - assertEnumValue(CrmAuditAction.DELETED, 3, "Deleted"); - assertEnumValue(CrmAuditAction.STAGE_CHANGED, 4, "Stage Changed"); - assertEnumValue(CrmAuditAction.OWNER_CHANGED, 5, "Owner Changed"); - assertEnumValue(CrmAuditAction.SCORE_CHANGED, 6, "Score Changed"); - assertEnumValue(CrmAuditAction.MERGED, 7, "Merged"); - assertEnumValue(CrmAuditAction.CONSENT_CHANGED, 8, "Consent Changed"); - assertEnumValue(CrmAuditAction.TAG_CHANGED, 9, "Tag Changed"); - assertEnumValue(CrmAuditAction.ENROLLED, 10, "Enrolled"); - assertEnumValue(CrmAuditAction.UNENROLLED, 11, "Unenrolled"); - assertEnumValue(CrmAuditAction.IMPORTED, 12, "Imported"); - assertEnumValue(CrmAuditAction.ANONYMIZED, 13, "Anonymized"); - assertEnumValue(CrmAuditAction.FORM_CONVERTED, 14, "Form Converted"); - - for(CrmAuditAction value : CrmAuditAction.values()) - { - assertThat(CrmAuditAction.getById(value.getId())).isEqualTo(value); - } - } - - - /******************************************************************************* ** Test CrmFormType *******************************************************************************/ diff --git a/src/test/java/com/kingsrook/qbits/crm/core/processes/BulkAddTagProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/core/processes/BulkAddTagProcessTest.java deleted file mode 100644 index 720ea82..0000000 --- a/src/test/java/com/kingsrook/qbits/crm/core/processes/BulkAddTagProcessTest.java +++ /dev/null @@ -1,183 +0,0 @@ -/******************************************************************************* - ** Unit tests for BulkAddTagProcess and BulkRemoveTagProcess. - *******************************************************************************/ -package com.kingsrook.qbits.crm.core.processes; - - -import com.kingsrook.qbits.crm.BaseTest; -import com.kingsrook.qbits.crm.core.model.Contact; -import com.kingsrook.qbits.crm.core.model.ContactTag; -import com.kingsrook.qbits.crm.core.model.Tag; -import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction; -import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; -import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; -import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput; -import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput; -import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; -import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; - - -/******************************************************************************* - ** Tests for BulkAddTag and BulkRemoveTag processes: adding tags, skipping - ** duplicates, and removing tags. - *******************************************************************************/ -class BulkAddTagProcessTest extends BaseTest -{ - - /******************************************************************************* - ** Add a tag to multiple contacts and verify junction rows are created. - *******************************************************************************/ - @Test - void testBulkAddTag() throws QException - { - /////////////////////////////////////// - // set up contacts and a tag // - /////////////////////////////////////// - Integer contactId1 = insertContact("Alice", "A"); - Integer contactId2 = insertContact("Bob", "B"); - Integer tagId = insertTag("VIP"); - - /////////////////////////////////////// - // run the BulkAddTag process // - /////////////////////////////////////// - RunProcessInput processInput = new RunProcessInput(); - processInput.setProcessName(BulkAddTagProcess.NAME); - processInput.addValue("tagId", tagId); - processInput.addValue("recordIds", contactId1 + "," + contactId2); - - RunProcessOutput processOutput = new RunProcessAction().execute(processInput); - - assertEquals(2, processOutput.getValues().get("addedCount")); - assertEquals(0, processOutput.getValues().get("skippedCount")); - - /////////////////////////////////////// - // verify junction rows created // - /////////////////////////////////////// - QueryOutput tagQuery = new QueryAction().execute( - new QueryInput(ContactTag.TABLE_NAME)); - assertEquals(2, tagQuery.getRecords().size()); - } - - - - /******************************************************************************* - ** Skip duplicate when the tag already exists on a contact. - *******************************************************************************/ - @Test - void testBulkAddTagSkipsDuplicates() throws QException - { - Integer contactId = insertContact("Alice", "A"); - Integer tagId = insertTag("VIP"); - - ///////////////////////////////////////////// - // manually insert the junction row first // - ///////////////////////////////////////////// - new InsertAction().execute( - new InsertInput(ContactTag.TABLE_NAME).withRecordEntity( - new ContactTag() - .withContactId(contactId) - .withTagId(tagId))); - - ///////////////////////////////////////////// - // run the process - should skip // - ///////////////////////////////////////////// - RunProcessInput processInput = new RunProcessInput(); - processInput.setProcessName(BulkAddTagProcess.NAME); - processInput.addValue("tagId", tagId); - processInput.addValue("recordIds", String.valueOf(contactId)); - - RunProcessOutput processOutput = new RunProcessAction().execute(processInput); - - assertEquals(0, processOutput.getValues().get("addedCount")); - assertEquals(1, processOutput.getValues().get("skippedCount")); - - ///////////////////////////////////////////// - // verify still only 1 junction row // - ///////////////////////////////////////////// - QueryOutput tagQuery = new QueryAction().execute( - new QueryInput(ContactTag.TABLE_NAME)); - assertEquals(1, tagQuery.getRecords().size()); - } - - - - /******************************************************************************* - ** Remove a tag from contacts via the BulkRemoveTag process. - *******************************************************************************/ - @Test - void testBulkRemoveTag() throws QException - { - Integer contactId = insertContact("Alice", "A"); - Integer tagId = insertTag("VIP"); - - ///////////////////////////////////////////// - // insert the junction row // - ///////////////////////////////////////////// - new InsertAction().execute( - new InsertInput(ContactTag.TABLE_NAME).withRecordEntity( - new ContactTag() - .withContactId(contactId) - .withTagId(tagId))); - - ///////////////////////////////////////////// - // verify junction row exists // - ///////////////////////////////////////////// - assertEquals(1, new QueryAction().execute( - new QueryInput(ContactTag.TABLE_NAME)).getRecords().size()); - - ///////////////////////////////////////////// - // run BulkRemoveTag // - ///////////////////////////////////////////// - RunProcessInput processInput = new RunProcessInput(); - processInput.setProcessName(BulkRemoveTagProcess.NAME); - processInput.addValue("tagId", tagId); - processInput.addValue("recordIds", String.valueOf(contactId)); - - RunProcessOutput processOutput = new RunProcessAction().execute(processInput); - - assertEquals(1, processOutput.getValues().get("removedCount")); - assertEquals(0, processOutput.getValues().get("skippedCount")); - - ///////////////////////////////////////////// - // verify junction row was deleted // - ///////////////////////////////////////////// - assertEquals(0, new QueryAction().execute( - new QueryInput(ContactTag.TABLE_NAME)).getRecords().size()); - } - - - - /*************************************************************************** - ** Helper: insert a Contact and return its id. - ***************************************************************************/ - private Integer insertContact(String firstName, String lastName) throws QException - { - InsertOutput output = new InsertAction().execute( - new InsertInput(Contact.TABLE_NAME).withRecordEntity( - new Contact() - .withFirstName(firstName) - .withLastName(lastName) - .withOwnerUserId("user-001"))); - return (output.getRecords().get(0).getValueInteger("id")); - } - - - - /*************************************************************************** - ** Helper: insert a Tag and return its id. - ***************************************************************************/ - private Integer insertTag(String name) throws QException - { - InsertOutput output = new InsertAction().execute( - new InsertInput(Tag.TABLE_NAME).withRecordEntity( - new Tag() - .withName(name))); - return (output.getRecords().get(0).getValueInteger("id")); - } - -} diff --git a/src/test/java/com/kingsrook/qbits/crm/core/processes/BulkAssignOwnerProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/core/processes/BulkAssignOwnerProcessTest.java index ff98288..7bf5fa7 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/processes/BulkAssignOwnerProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/processes/BulkAssignOwnerProcessTest.java @@ -1,10 +1,31 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for BulkAssignOwnerProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.processes; -import java.util.List; import com.kingsrook.qbits.crm.BaseTest; import com.kingsrook.qbits.crm.core.model.Contact; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; diff --git a/src/test/java/com/kingsrook/qbits/crm/core/processes/ConvertFormToContactProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/core/processes/ConvertFormToContactProcessTest.java index 16a6c75..22f4a7b 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/processes/ConvertFormToContactProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/processes/ConvertFormToContactProcessTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for ConvertFormToContactProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.processes; @@ -24,11 +46,9 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; -import com.kingsrook.qqq.backend.core.model.data.QRecord; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; /******************************************************************************* diff --git a/src/test/java/com/kingsrook/qbits/crm/core/processes/DetectDuplicatesProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/core/processes/DetectDuplicatesProcessTest.java index d597370..cc0c144 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/processes/DetectDuplicatesProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/processes/DetectDuplicatesProcessTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for DetectDuplicatesProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.processes; @@ -95,6 +117,9 @@ class DetectDuplicatesProcessTest extends BaseTest + /******************************************************************************* + ** Insert Contact. + *******************************************************************************/ private void insertContact(String email, String firstName, String lastName) throws QException { new InsertAction().execute( @@ -108,6 +133,9 @@ class DetectDuplicatesProcessTest extends BaseTest + /******************************************************************************* + ** Insert Company. + *******************************************************************************/ private void insertCompany(String name, String domain) throws QException { new InsertAction().execute( diff --git a/src/test/java/com/kingsrook/qbits/crm/core/processes/GdprAnonymizeContactProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/core/processes/GdprAnonymizeContactProcessTest.java index 9740c02..550f993 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/processes/GdprAnonymizeContactProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/processes/GdprAnonymizeContactProcessTest.java @@ -1,40 +1,50 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for GdprAnonymizeContactProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.processes; import com.kingsrook.qbits.crm.BaseTest; -import com.kingsrook.qbits.crm.audit.model.AuditLog; import com.kingsrook.qbits.crm.core.model.ConsentRecord; import com.kingsrook.qbits.crm.core.model.Contact; -import com.kingsrook.qbits.crm.core.model.enums.CrmAuditAction; import com.kingsrook.qbits.crm.core.model.enums.CrmConsentStatus; import com.kingsrook.qbits.crm.core.model.enums.CrmConsentType; -import com.kingsrook.qbits.crm.core.model.enums.CrmEntityType; import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction; import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; -import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; -import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput; -import com.kingsrook.qqq.backend.core.model.data.QRecord; -import java.util.List; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -100,109 +110,6 @@ class GdprAnonymizeContactProcessTest extends BaseTest assertEquals(CrmConsentStatus.WITHDRAWN.getId(), consent.getStatus()); assertEquals(CrmConsentType.DATA_PROCESSING.getId(), consent.getConsentType()); - ///////////////////////////////////////////// - // verify audit log entry created // - ///////////////////////////////////////////// - QueryOutput auditQuery = new QueryAction().execute( - new QueryInput(AuditLog.TABLE_NAME)); - assertTrue(auditQuery.getRecords().size() >= 1); - } - - - - /******************************************************************************* - ** Verify that audit log entries are anonymized after GDPR process runs. - *******************************************************************************/ - @Test - void testAuditLogScrubbing() throws QException - { - /////////////////////////////////////// - // create a contact // - /////////////////////////////////////// - Integer contactId = insertContact(); - - /////////////////////////////////////// - // insert a pre-existing audit entry // - /////////////////////////////////////// - new InsertAction().execute( - new InsertInput(AuditLog.TABLE_NAME).withRecordEntity( - new AuditLog() - .withEntityType(CrmEntityType.CONTACT.getId()) - .withEntityId(contactId) - .withAction(CrmAuditAction.UPDATED.getId()) - .withUserId("test-user-1") - .withFieldName("email") - .withOldValue("old@example.com") - .withNewValue("new@example.com") - .withMessage("Email changed"))); - - //////////////////////////////////// - // run the anonymize process // - //////////////////////////////////// - RunProcessInput processInput = new RunProcessInput(); - processInput.setProcessName(GdprAnonymizeContactProcess.NAME); - processInput.addValue("contactId", contactId); - new RunProcessAction().execute(processInput); - - ///////////////////////////////////////////// - // query audit entries for this contact // - ///////////////////////////////////////////// - QueryOutput auditQuery = new QueryAction().execute( - new QueryInput(AuditLog.TABLE_NAME) - .withFilter(new QQueryFilter() - .withCriteria(new QFilterCriteria("entityType", QCriteriaOperator.EQUALS, CrmEntityType.CONTACT.getId())) - .withCriteria(new QFilterCriteria("entityId", QCriteriaOperator.EQUALS, contactId)))); - - ///////////////////////////////////////////// - // find the pre-existing entry (not the // - // ANONYMIZED action log entry itself) // - ///////////////////////////////////////////// - boolean foundScrubbed = false; - for(QRecord record : auditQuery.getRecords()) - { - AuditLog log = new AuditLog(record); - if(CrmAuditAction.UPDATED.getId().equals(log.getAction())) - { - assertEquals("[ANONYMIZED]", log.getOldValue()); - assertEquals("[ANONYMIZED]", log.getNewValue()); - assertEquals("[ANONYMIZED]", log.getMessage()); - foundScrubbed = true; - } - } - assertTrue(foundScrubbed, "Expected at least one scrubbed audit log entry"); - } - - - - /******************************************************************************* - ** Verify that normal (non-GDPR) audit log updates still throw exceptions. - *******************************************************************************/ - @Test - void testAuditLogImmutabilityEnforced() throws QException - { - /////////////////////////////////////// - // insert an audit log entry // - /////////////////////////////////////// - InsertOutput insertOutput = new InsertAction().execute( - new InsertInput(AuditLog.TABLE_NAME).withRecordEntity( - new AuditLog() - .withEntityType(CrmEntityType.CONTACT.getId()) - .withEntityId(999) - .withAction(CrmAuditAction.CREATED.getId()) - .withUserId("test-user-1") - .withMessage("Record created"))); - - Integer auditId = insertOutput.getRecords().get(0).getValueInteger("id"); - - /////////////////////////////////////// - // attempt to update without bypass // - /////////////////////////////////////// - QRecord update = new QRecord() - .withValue("id", auditId) - .withValue("message", "tampered"); - - assertThrows(QUserFacingException.class, () -> - new UpdateAction().execute(new UpdateInput(AuditLog.TABLE_NAME).withRecords(List.of(update)))); } diff --git a/src/test/java/com/kingsrook/qbits/crm/core/processes/ImportContactsProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/core/processes/ImportContactsProcessTest.java index d27bfe9..6dde653 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/processes/ImportContactsProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/processes/ImportContactsProcessTest.java @@ -1,13 +1,34 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for ImportContactsProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.processes; import java.util.ArrayList; import java.util.List; import com.kingsrook.qbits.crm.BaseTest; -import com.kingsrook.qbits.crm.audit.model.AuditLog; import com.kingsrook.qbits.crm.core.model.Contact; import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; @@ -59,13 +80,6 @@ class ImportContactsProcessTest extends BaseTest new QueryInput(Contact.TABLE_NAME)); assertEquals(2, contactQuery.getRecords().size()); - /////////////////////////////////////////////////////////////////////////// - // 2 CREATED entries from CrmAuditLogCustomizer on contact insert + // - // 2 IMPORTED entries from the import process itself = 4 total // - /////////////////////////////////////////////////////////////////////////// - QueryOutput auditQuery = new QueryAction().execute( - new QueryInput(AuditLog.TABLE_NAME)); - assertEquals(4, auditQuery.getRecords().size()); } diff --git a/src/test/java/com/kingsrook/qbits/crm/core/processes/MergeCompaniesProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/core/processes/MergeCompaniesProcessTest.java index 2b21c17..1095170 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/processes/MergeCompaniesProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/processes/MergeCompaniesProcessTest.java @@ -1,12 +1,33 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for MergeCompaniesProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.processes; import java.math.BigDecimal; import com.kingsrook.qbits.crm.BaseTest; -import com.kingsrook.qbits.crm.audit.model.AuditLog; import com.kingsrook.qbits.crm.core.model.Company; import com.kingsrook.qbits.crm.core.model.Contact; import com.kingsrook.qbits.crm.deals.model.Deal; @@ -15,20 +36,13 @@ import com.kingsrook.qbits.crm.deals.model.PipelineStage; import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction; import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; -import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; /******************************************************************************* @@ -88,16 +102,13 @@ class MergeCompaniesProcessTest extends BaseTest Deal updatedDeal = new Deal(GetAction.execute(Deal.TABLE_NAME, dealId)); assertEquals(primaryId, updatedDeal.getCompanyId()); - ///////////////////////////////////////////// - // verify audit logs created // - ///////////////////////////////////////////// - QueryOutput auditQuery = new QueryAction().execute( - new QueryInput(AuditLog.TABLE_NAME)); - assertTrue(auditQuery.getRecords().size() >= 2); } + /******************************************************************************* + ** Insert Company. + *******************************************************************************/ private Integer insertCompany(String name, String domain) throws QException { InsertOutput output = new InsertAction().execute( @@ -111,6 +122,9 @@ class MergeCompaniesProcessTest extends BaseTest + /******************************************************************************* + ** Insert Contact. + *******************************************************************************/ private Integer insertContact(Integer companyId) throws QException { InsertOutput output = new InsertAction().execute( @@ -126,6 +140,9 @@ class MergeCompaniesProcessTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline. + *******************************************************************************/ private Integer insertPipeline() throws QException { InsertOutput output = new InsertAction().execute( @@ -136,6 +153,9 @@ class MergeCompaniesProcessTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline Stage. + *******************************************************************************/ private Integer insertPipelineStage(Integer pipelineId) throws QException { InsertOutput output = new InsertAction().execute( @@ -150,6 +170,9 @@ class MergeCompaniesProcessTest extends BaseTest + /******************************************************************************* + ** Insert Deal. + *******************************************************************************/ private Integer insertDeal(Integer companyId, Integer pipelineId, Integer stageId) throws QException { InsertOutput output = new InsertAction().execute( diff --git a/src/test/java/com/kingsrook/qbits/crm/core/processes/MergeContactsProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/core/processes/MergeContactsProcessTest.java index 94124af..da66bb2 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/processes/MergeContactsProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/processes/MergeContactsProcessTest.java @@ -1,16 +1,35 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for MergeContactsProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.processes; import com.kingsrook.qbits.crm.BaseTest; import com.kingsrook.qbits.crm.activities.model.Activity; import com.kingsrook.qbits.crm.activities.model.ActivityType; -import com.kingsrook.qbits.crm.audit.model.AuditLog; import com.kingsrook.qbits.crm.core.model.Contact; -import com.kingsrook.qbits.crm.core.model.ContactTag; -import com.kingsrook.qbits.crm.core.model.Tag; import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction; import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; @@ -24,11 +43,9 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; -import com.kingsrook.qqq.backend.core.model.data.QRecord; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; /******************************************************************************* @@ -63,16 +80,6 @@ class MergeContactsProcessTest extends BaseTest .withOwnerUserId("user-001") .withIsCompleted(false))); - /////////////////////////////////////// - // create tags on both contacts // - /////////////////////////////////////// - Integer tag1Id = insertTag("VIP"); - Integer tag2Id = insertTag("Prospect"); - - insertContactTag(primaryId, tag1Id); - insertContactTag(secondaryId, tag1Id); // duplicate - insertContactTag(secondaryId, tag2Id); // unique - //////////////////////////////////// // run merge process // //////////////////////////////////// @@ -97,21 +104,6 @@ class MergeContactsProcessTest extends BaseTest .withCriteria(new QFilterCriteria("contactId", QCriteriaOperator.EQUALS, primaryId)))); assertEquals(1, activities.getRecords().size()); - ///////////////////////////////////////////// - // verify tags: primary should have both // - ///////////////////////////////////////////// - QueryOutput tags = new QueryAction().execute( - new QueryInput(ContactTag.TABLE_NAME) - .withFilter(new QQueryFilter() - .withCriteria(new QFilterCriteria("contactId", QCriteriaOperator.EQUALS, primaryId)))); - assertEquals(2, tags.getRecords().size()); - - ///////////////////////////////////////////// - // verify audit logs created // - ///////////////////////////////////////////// - QueryOutput auditQuery = new QueryAction().execute( - new QueryInput(AuditLog.TABLE_NAME)); - assertTrue(auditQuery.getRecords().size() >= 2); } @@ -133,6 +125,9 @@ class MergeContactsProcessTest extends BaseTest + /******************************************************************************* + ** Insert Activity Type. + *******************************************************************************/ private Integer insertActivityType(String name) throws QException { InsertOutput output = new InsertAction().execute( @@ -148,23 +143,4 @@ class MergeContactsProcessTest extends BaseTest - private Integer insertTag(String name) throws QException - { - InsertOutput output = new InsertAction().execute( - new InsertInput(Tag.TABLE_NAME).withRecordEntity( - new Tag().withName(name))); - return (output.getRecords().get(0).getValueInteger("id")); - } - - - - private void insertContactTag(Integer contactId, Integer tagId) throws QException - { - new InsertAction().execute( - new InsertInput(ContactTag.TABLE_NAME).withRecord( - new QRecord() - .withValue("contactId", contactId) - .withValue("tagId", tagId))); - } - } diff --git a/src/test/java/com/kingsrook/qbits/crm/core/processes/SubscribeToListProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/core/processes/SubscribeToListProcessTest.java index d4fa125..a816a34 100644 --- a/src/test/java/com/kingsrook/qbits/crm/core/processes/SubscribeToListProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/core/processes/SubscribeToListProcessTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for SubscribeToListProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.core.processes; diff --git a/src/test/java/com/kingsrook/qbits/crm/deals/DealContactTest.java b/src/test/java/com/kingsrook/qbits/crm/deals/DealContactTest.java index 99cc402..2cb9343 100644 --- a/src/test/java/com/kingsrook/qbits/crm/deals/DealContactTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/deals/DealContactTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for the DealContact entity. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals; @@ -23,7 +45,6 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/src/test/java/com/kingsrook/qbits/crm/deals/DealCoverageTest.java b/src/test/java/com/kingsrook/qbits/crm/deals/DealCoverageTest.java index f11224c..87647b7 100644 --- a/src/test/java/com/kingsrook/qbits/crm/deals/DealCoverageTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/deals/DealCoverageTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Coverage tests for Deal entity -- exercises every getter/setter/withX. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals; diff --git a/src/test/java/com/kingsrook/qbits/crm/deals/DealProductTest.java b/src/test/java/com/kingsrook/qbits/crm/deals/DealProductTest.java index 4ad2d65..81cebf2 100644 --- a/src/test/java/com/kingsrook/qbits/crm/deals/DealProductTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/deals/DealProductTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for the DealProduct entity. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals; diff --git a/src/test/java/com/kingsrook/qbits/crm/deals/DealStageHistoryTest.java b/src/test/java/com/kingsrook/qbits/crm/deals/DealStageHistoryTest.java index ab5b979..03ad166 100644 --- a/src/test/java/com/kingsrook/qbits/crm/deals/DealStageHistoryTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/deals/DealStageHistoryTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for the DealStageHistory entity. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals; diff --git a/src/test/java/com/kingsrook/qbits/crm/deals/DealTest.java b/src/test/java/com/kingsrook/qbits/crm/deals/DealTest.java index 3b7c3fc..1156803 100644 --- a/src/test/java/com/kingsrook/qbits/crm/deals/DealTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/deals/DealTest.java @@ -1,19 +1,40 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for the Deal entity. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals; import java.math.BigDecimal; -import java.time.Instant; import java.time.LocalDate; import com.kingsrook.qbits.crm.BaseTest; +import com.kingsrook.qbits.crm.core.model.enums.CrmDealPriority; +import com.kingsrook.qbits.crm.core.model.enums.CrmWinLossType; import com.kingsrook.qbits.crm.deals.model.Deal; import com.kingsrook.qbits.crm.deals.model.Pipeline; import com.kingsrook.qbits.crm.deals.model.PipelineStage; import com.kingsrook.qbits.crm.deals.model.WinLossReason; -import com.kingsrook.qbits.crm.core.model.enums.CrmDealPriority; -import com.kingsrook.qbits.crm.core.model.enums.CrmWinLossType; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.context.QContext; diff --git a/src/test/java/com/kingsrook/qbits/crm/deals/PipelineTest.java b/src/test/java/com/kingsrook/qbits/crm/deals/PipelineTest.java index 1afce7a..89f6724 100644 --- a/src/test/java/com/kingsrook/qbits/crm/deals/PipelineTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/deals/PipelineTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for the Pipeline and PipelineStage entities. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals; diff --git a/src/test/java/com/kingsrook/qbits/crm/deals/ProductTest.java b/src/test/java/com/kingsrook/qbits/crm/deals/ProductTest.java index 498aa89..2481816 100644 --- a/src/test/java/com/kingsrook/qbits/crm/deals/ProductTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/deals/ProductTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for the Product entity. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals; diff --git a/src/test/java/com/kingsrook/qbits/crm/deals/customizers/DealInitializationCustomizerTest.java b/src/test/java/com/kingsrook/qbits/crm/deals/customizers/DealInitializationCustomizerTest.java index 689eea9..a0065ef 100644 --- a/src/test/java/com/kingsrook/qbits/crm/deals/customizers/DealInitializationCustomizerTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/deals/customizers/DealInitializationCustomizerTest.java @@ -1,8 +1,30 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for DealInitializationCustomizer -- verifies that inserting a ** deal sets stageEnteredDate, weightedAmount, and creates the initial ** DealStageHistory row. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.customizers; diff --git a/src/test/java/com/kingsrook/qbits/crm/deals/customizers/DealProductRecalculationCustomizerTest.java b/src/test/java/com/kingsrook/qbits/crm/deals/customizers/DealProductRecalculationCustomizerTest.java index 25e207c..438eb09 100644 --- a/src/test/java/com/kingsrook/qbits/crm/deals/customizers/DealProductRecalculationCustomizerTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/deals/customizers/DealProductRecalculationCustomizerTest.java @@ -1,8 +1,30 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for DealProductRecalculationCustomizer -- verifies that ** inserting, updating, and deleting DealProduct rows correctly recalculates ** totalAmount on the line item and rolls up to the parent Deal's amount. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.customizers; diff --git a/src/test/java/com/kingsrook/qbits/crm/deals/customizers/DealStageChangeCustomizerTest.java b/src/test/java/com/kingsrook/qbits/crm/deals/customizers/DealStageChangeCustomizerTest.java index 2059a48..8cb4ae0 100644 --- a/src/test/java/com/kingsrook/qbits/crm/deals/customizers/DealStageChangeCustomizerTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/deals/customizers/DealStageChangeCustomizerTest.java @@ -1,14 +1,35 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for DealStageChangeCustomizer -- verifies that updating a deal's ** pipelineStageId triggers recalculation of weightedAmount, stageEnteredDate, ** actualCloseDate, and DealStageHistory creation. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.customizers; import java.math.BigDecimal; import java.time.Instant; -import java.time.temporal.ChronoUnit; import com.kingsrook.qbits.crm.BaseTest; import com.kingsrook.qbits.crm.deals.model.Deal; import com.kingsrook.qbits.crm.deals.model.DealStageHistory; @@ -33,7 +54,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; /******************************************************************************* diff --git a/src/test/java/com/kingsrook/qbits/crm/deals/processes/CloneDealProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/deals/processes/CloneDealProcessTest.java index fd97890..54e77de 100644 --- a/src/test/java/com/kingsrook/qbits/crm/deals/processes/CloneDealProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/deals/processes/CloneDealProcessTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CloneDealProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.processes; @@ -9,7 +31,6 @@ import com.kingsrook.qbits.crm.BaseTest; import com.kingsrook.qbits.crm.deals.model.Deal; import com.kingsrook.qbits.crm.deals.model.DealContact; import com.kingsrook.qbits.crm.deals.model.DealProduct; -import com.kingsrook.qbits.crm.deals.model.DealTag; import com.kingsrook.qbits.crm.deals.model.Pipeline; import com.kingsrook.qbits.crm.deals.model.PipelineStage; import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction; @@ -31,7 +52,6 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; /******************************************************************************* @@ -63,7 +83,6 @@ class CloneDealProcessTest extends BaseTest /////////////////////////////////////// insertDealContact(dealId, 42); insertDealProduct(dealId, 100, 2, new BigDecimal("5000")); - insertDealTag(dealId, 10); //////////////////////////////////// // run the CloneDeal process // @@ -102,11 +121,6 @@ class CloneDealProcessTest extends BaseTest .withCriteria(new QFilterCriteria("dealId", QCriteriaOperator.EQUALS, newDealId)))); assertEquals(1, dealProducts.getRecords().size()); - QueryOutput dealTags = new QueryAction().execute( - new QueryInput(DealTag.TABLE_NAME) - .withFilter(new QQueryFilter() - .withCriteria(new QFilterCriteria("dealId", QCriteriaOperator.EQUALS, newDealId)))); - assertEquals(1, dealTags.getRecords().size()); } @@ -189,16 +203,4 @@ class CloneDealProcessTest extends BaseTest - /*************************************************************************** - ** Helper: insert a DealTag. - ***************************************************************************/ - private void insertDealTag(Integer dealId, Integer tagId) throws QException - { - new InsertAction().execute( - new InsertInput(DealTag.TABLE_NAME).withRecord( - new QRecord() - .withValue("dealId", dealId) - .withValue("tagId", tagId))); - } - } diff --git a/src/test/java/com/kingsrook/qbits/crm/deals/processes/ConvertLeadProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/deals/processes/ConvertLeadProcessTest.java index 759793a..725186f 100644 --- a/src/test/java/com/kingsrook/qbits/crm/deals/processes/ConvertLeadProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/deals/processes/ConvertLeadProcessTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for ConvertLeadProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.processes; diff --git a/src/test/java/com/kingsrook/qbits/crm/deals/processes/ManageContactOnDealProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/deals/processes/ManageContactOnDealProcessTest.java index 61ed550..48b38a1 100644 --- a/src/test/java/com/kingsrook/qbits/crm/deals/processes/ManageContactOnDealProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/deals/processes/ManageContactOnDealProcessTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for ManageContactOnDealProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.processes; @@ -29,7 +51,6 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; /******************************************************************************* diff --git a/src/test/java/com/kingsrook/qbits/crm/deals/processes/MoveDealStageProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/deals/processes/MoveDealStageProcessTest.java index da70f84..3fc3f0c 100644 --- a/src/test/java/com/kingsrook/qbits/crm/deals/processes/MoveDealStageProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/deals/processes/MoveDealStageProcessTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for MoveDealStageProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.processes; @@ -8,8 +30,6 @@ import java.math.BigDecimal; import java.time.Instant; import java.time.temporal.ChronoUnit; import com.kingsrook.qbits.crm.BaseTest; -import com.kingsrook.qbits.crm.audit.model.AuditLog; -import com.kingsrook.qbits.crm.core.model.enums.CrmAuditAction; import com.kingsrook.qbits.crm.deals.model.Deal; import com.kingsrook.qbits.crm.deals.model.DealStageHistory; import com.kingsrook.qbits.crm.deals.model.Pipeline; @@ -21,7 +41,6 @@ import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput; -import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; @@ -29,13 +48,11 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; -import com.kingsrook.qqq.backend.core.model.data.QRecord; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; /******************************************************************************* @@ -265,43 +282,6 @@ class MoveDealStageProcessTest extends BaseTest - /******************************************************************************* - ** Verify that an audit log entry with STAGE_CHANGED is created. - *******************************************************************************/ - @Test - void testAuditLogCreated() throws QException - { - Integer pipelineId = insertPipeline("Audit Pipeline"); - Integer stage1Id = insertStage(pipelineId, "Step 1", 1, 10, false, false, null, null); - Integer stage2Id = insertStage(pipelineId, "Step 2", 2, 50, false, false, null, null); - - Integer dealId = insertDeal("Audit Deal", pipelineId, stage1Id, new BigDecimal("3000")); - - RunProcessInput processInput = new RunProcessInput(); - processInput.setProcessName(MoveDealStageProcess.NAME); - processInput.addValue("dealId", dealId); - processInput.addValue("targetStageId", stage2Id); - - new RunProcessAction().execute(processInput); - - /////////////////////////////////////////// - // verify audit log entry // - /////////////////////////////////////////// - QueryOutput auditOutput = new QueryAction().execute( - new QueryInput(AuditLog.TABLE_NAME) - .withFilter(new QQueryFilter() - .withCriteria(new QFilterCriteria("entityId", QCriteriaOperator.EQUALS, dealId)) - .withCriteria(new QFilterCriteria("action", QCriteriaOperator.EQUALS, CrmAuditAction.STAGE_CHANGED.getId())))); - - assertTrue(auditOutput.getRecords().size() >= 1); - AuditLog audit = new AuditLog(auditOutput.getRecords().get(0)); - assertEquals("pipelineStageId", audit.getFieldName()); - assertEquals(String.valueOf(stage1Id), audit.getOldValue()); - assertEquals(String.valueOf(stage2Id), audit.getNewValue()); - } - - - /*************************************************************************** ** Helper: insert a Pipeline and return its id. ***************************************************************************/ diff --git a/src/test/java/com/kingsrook/qbits/crm/deals/processes/ReopenDealProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/deals/processes/ReopenDealProcessTest.java index 4b0a24a..c707436 100644 --- a/src/test/java/com/kingsrook/qbits/crm/deals/processes/ReopenDealProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/deals/processes/ReopenDealProcessTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for ReopenDealProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.processes; diff --git a/src/test/java/com/kingsrook/qbits/crm/deals/processes/TransferOwnershipProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/deals/processes/TransferOwnershipProcessTest.java index 2a3d63b..040d098 100644 --- a/src/test/java/com/kingsrook/qbits/crm/deals/processes/TransferOwnershipProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/deals/processes/TransferOwnershipProcessTest.java @@ -1,12 +1,33 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for TransferOwnershipProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.deals.processes; import java.math.BigDecimal; import com.kingsrook.qbits.crm.BaseTest; -import com.kingsrook.qbits.crm.audit.model.AuditLog; import com.kingsrook.qbits.crm.core.model.Company; import com.kingsrook.qbits.crm.core.model.Contact; import com.kingsrook.qbits.crm.deals.model.Deal; @@ -15,17 +36,12 @@ import com.kingsrook.qbits.crm.deals.model.PipelineStage; import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction; import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; -import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; -import com.kingsrook.qqq.backend.core.model.data.QRecord; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; /******************************************************************************* @@ -78,12 +94,6 @@ class TransferOwnershipProcessTest extends BaseTest Deal updatedDeal = new Deal(GetAction.execute(Deal.TABLE_NAME, dealId)); assertEquals("user-new", updatedDeal.getOwnerUserId()); - ///////////////////////////////////////////// - // verify audit log entries created // - ///////////////////////////////////////////// - QueryOutput auditQuery = new QueryAction().execute( - new QueryInput(AuditLog.TABLE_NAME)); - assertTrue(auditQuery.getRecords().size() >= 3); } @@ -121,6 +131,9 @@ class TransferOwnershipProcessTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline. + *******************************************************************************/ private Integer insertPipeline() throws QException { InsertOutput output = new InsertAction().execute( @@ -131,6 +144,9 @@ class TransferOwnershipProcessTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline Stage. + *******************************************************************************/ private Integer insertPipelineStage(Integer pipelineId) throws QException { InsertOutput output = new InsertAction().execute( @@ -145,6 +161,9 @@ class TransferOwnershipProcessTest extends BaseTest + /******************************************************************************* + ** Insert Deal. + *******************************************************************************/ private Integer insertDeal(String ownerUserId, Integer pipelineId, Integer stageId) throws QException { InsertOutput output = new InsertAction().execute( diff --git a/src/test/java/com/kingsrook/qbits/crm/email/EmailMessageTest.java b/src/test/java/com/kingsrook/qbits/crm/email/EmailMessageTest.java index 24f16c7..77d97f1 100644 --- a/src/test/java/com/kingsrook/qbits/crm/email/EmailMessageTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/email/EmailMessageTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for the EmailMessage entity. *******************************************************************************/ + package com.kingsrook.qbits.crm.email; diff --git a/src/test/java/com/kingsrook/qbits/crm/email/EmailSequenceTest.java b/src/test/java/com/kingsrook/qbits/crm/email/EmailSequenceTest.java index b03bc64..69bb010 100644 --- a/src/test/java/com/kingsrook/qbits/crm/email/EmailSequenceTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/email/EmailSequenceTest.java @@ -1,9 +1,32 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for the EmailSequence entity. *******************************************************************************/ + package com.kingsrook.qbits.crm.email; +import java.time.Instant; import com.kingsrook.qbits.crm.BaseTest; import com.kingsrook.qbits.crm.core.model.enums.CrmEnrollmentStatus; import com.kingsrook.qbits.crm.core.model.enums.CrmSequenceStepType; @@ -20,7 +43,6 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; import org.junit.jupiter.api.Test; -import java.time.Instant; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; diff --git a/src/test/java/com/kingsrook/qbits/crm/email/EmailTemplateTest.java b/src/test/java/com/kingsrook/qbits/crm/email/EmailTemplateTest.java index eb91d99..34e8dac 100644 --- a/src/test/java/com/kingsrook/qbits/crm/email/EmailTemplateTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/email/EmailTemplateTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for the EmailTemplate entity. *******************************************************************************/ + package com.kingsrook.qbits.crm.email; diff --git a/src/test/java/com/kingsrook/qbits/crm/email/SequenceEnrollmentTest.java b/src/test/java/com/kingsrook/qbits/crm/email/SequenceEnrollmentTest.java index 6b6622e..b9da86c 100644 --- a/src/test/java/com/kingsrook/qbits/crm/email/SequenceEnrollmentTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/email/SequenceEnrollmentTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for the SequenceEnrollment entity. *******************************************************************************/ + package com.kingsrook.qbits.crm.email; diff --git a/src/test/java/com/kingsrook/qbits/crm/email/customizers/EmailTemplatePreDeleteCustomizerTest.java b/src/test/java/com/kingsrook/qbits/crm/email/customizers/EmailTemplatePreDeleteCustomizerTest.java index 0e4215d..ef6d057 100644 --- a/src/test/java/com/kingsrook/qbits/crm/email/customizers/EmailTemplatePreDeleteCustomizerTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/email/customizers/EmailTemplatePreDeleteCustomizerTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for EmailTemplatePreDeleteCustomizer. *******************************************************************************/ + package com.kingsrook.qbits.crm.email.customizers; diff --git a/src/test/java/com/kingsrook/qbits/crm/email/processes/EnrollInSequenceProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/email/processes/EnrollInSequenceProcessTest.java index a5ef12d..23a97cd 100644 --- a/src/test/java/com/kingsrook/qbits/crm/email/processes/EnrollInSequenceProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/email/processes/EnrollInSequenceProcessTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for EnrollInSequenceProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.email.processes; diff --git a/src/test/java/com/kingsrook/qbits/crm/email/processes/ProcessSequenceStepsProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/email/processes/ProcessSequenceStepsProcessTest.java index df0a838..8dcd90f 100644 --- a/src/test/java/com/kingsrook/qbits/crm/email/processes/ProcessSequenceStepsProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/email/processes/ProcessSequenceStepsProcessTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for ProcessSequenceStepsProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.email.processes; diff --git a/src/test/java/com/kingsrook/qbits/crm/email/processes/SendEmailProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/email/processes/SendEmailProcessTest.java index 89be5d9..78112a6 100644 --- a/src/test/java/com/kingsrook/qbits/crm/email/processes/SendEmailProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/email/processes/SendEmailProcessTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for SendEmailProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.email.processes; diff --git a/src/test/java/com/kingsrook/qbits/crm/email/processes/TrackEmailEventProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/email/processes/TrackEmailEventProcessTest.java index 906f5d3..faa99ae 100644 --- a/src/test/java/com/kingsrook/qbits/crm/email/processes/TrackEmailEventProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/email/processes/TrackEmailEventProcessTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for TrackEmailEventProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.email.processes; @@ -17,11 +39,9 @@ import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; -import com.kingsrook.qqq.backend.core.model.data.QRecord; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/src/test/java/com/kingsrook/qbits/crm/scoring/AssignmentRuleTest.java b/src/test/java/com/kingsrook/qbits/crm/scoring/AssignmentRuleTest.java index 6888ff0..fe2f00b 100644 --- a/src/test/java/com/kingsrook/qbits/crm/scoring/AssignmentRuleTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/scoring/AssignmentRuleTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for the AssignmentRule entity. *******************************************************************************/ + package com.kingsrook.qbits.crm.scoring; diff --git a/src/test/java/com/kingsrook/qbits/crm/scoring/LeadScoreRuleTest.java b/src/test/java/com/kingsrook/qbits/crm/scoring/LeadScoreRuleTest.java index 5edf83e..99d562e 100644 --- a/src/test/java/com/kingsrook/qbits/crm/scoring/LeadScoreRuleTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/scoring/LeadScoreRuleTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for the LeadScoreRule entity. *******************************************************************************/ + package com.kingsrook.qbits.crm.scoring; diff --git a/src/test/java/com/kingsrook/qbits/crm/scoring/SalesGoalTest.java b/src/test/java/com/kingsrook/qbits/crm/scoring/SalesGoalTest.java index d14668c..f99c917 100644 --- a/src/test/java/com/kingsrook/qbits/crm/scoring/SalesGoalTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/scoring/SalesGoalTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for the SalesGoal entity. *******************************************************************************/ + package com.kingsrook.qbits.crm.scoring; diff --git a/src/test/java/com/kingsrook/qbits/crm/scoring/processes/AutoAssignProcessCoverageTest.java b/src/test/java/com/kingsrook/qbits/crm/scoring/processes/AutoAssignProcessCoverageTest.java index cfd503a..0de319b 100644 --- a/src/test/java/com/kingsrook/qbits/crm/scoring/processes/AutoAssignProcessCoverageTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/scoring/processes/AutoAssignProcessCoverageTest.java @@ -1,10 +1,34 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Additional coverage tests for AutoAssignProcess: LEAST_ACTIVE strategy, ** criteria JSON matching, invalid entity type, missing record. *******************************************************************************/ + package com.kingsrook.qbits.crm.scoring.processes; +import java.math.BigDecimal; +import java.time.Instant; import com.kingsrook.qbits.crm.BaseTest; import com.kingsrook.qbits.crm.core.model.Contact; import com.kingsrook.qbits.crm.core.model.enums.CrmAssignStrategy; @@ -15,17 +39,12 @@ import com.kingsrook.qbits.crm.deals.model.PipelineStage; import com.kingsrook.qbits.crm.scoring.model.AssignmentRule; import com.kingsrook.qbits.crm.scoring.model.AssignmentRuleMember; import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction; -import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput; -import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; -import java.math.BigDecimal; -import java.time.Instant; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -240,6 +259,9 @@ class AutoAssignProcessCoverageTest extends BaseTest + /******************************************************************************* + ** Insert Contact. + *******************************************************************************/ private Integer insertContact(String firstName, String lastName) throws QException { InsertOutput output = new InsertAction().execute( @@ -254,6 +276,9 @@ class AutoAssignProcessCoverageTest extends BaseTest + /******************************************************************************* + ** Insert Contact With State. + *******************************************************************************/ private Integer insertContactWithState(String firstName, String lastName, String state) throws QException { InsertOutput output = new InsertAction().execute( @@ -269,6 +294,9 @@ class AutoAssignProcessCoverageTest extends BaseTest + /******************************************************************************* + ** Insert Deal. + *******************************************************************************/ private Integer insertDeal(String name) throws QException { Integer pipelineId = new InsertAction().execute( @@ -298,6 +326,9 @@ class AutoAssignProcessCoverageTest extends BaseTest + /******************************************************************************* + ** Run Auto Assign. + *******************************************************************************/ private RunProcessOutput runAutoAssign(String entityType, Integer recordId) throws QException { RunProcessInput processInput = new RunProcessInput(); diff --git a/src/test/java/com/kingsrook/qbits/crm/scoring/processes/AutoAssignProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/scoring/processes/AutoAssignProcessTest.java index 99818d4..5e1c411 100644 --- a/src/test/java/com/kingsrook/qbits/crm/scoring/processes/AutoAssignProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/scoring/processes/AutoAssignProcessTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for AutoAssignProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.scoring.processes; @@ -22,7 +44,6 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; /******************************************************************************* diff --git a/src/test/java/com/kingsrook/qbits/crm/scoring/processes/CalculateLeadScoresCoverageTest.java b/src/test/java/com/kingsrook/qbits/crm/scoring/processes/CalculateLeadScoresCoverageTest.java index 673c7d2..718c93e 100644 --- a/src/test/java/com/kingsrook/qbits/crm/scoring/processes/CalculateLeadScoresCoverageTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/scoring/processes/CalculateLeadScoresCoverageTest.java @@ -1,7 +1,29 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Additional coverage tests for CalculateLeadScoresProcess: operators ** CONTAINS, GT, LT, NOT_EQUALS, IS_NOT_SET, and invalid operator. *******************************************************************************/ + package com.kingsrook.qbits.crm.scoring.processes; @@ -191,6 +213,9 @@ class CalculateLeadScoresCoverageTest extends BaseTest + /******************************************************************************* + ** Insert Rule. + *******************************************************************************/ private void insertRule(String name, String fieldPath, Integer operator, String fieldValue, Integer scoreAdj, Integer sortOrder) throws QException { @@ -209,6 +234,9 @@ class CalculateLeadScoresCoverageTest extends BaseTest + /******************************************************************************* + ** Insert Contact. + *******************************************************************************/ private Integer insertContact(String firstName, String lastName, String email, String jobTitle, Integer leadScore) throws QException { @@ -231,6 +259,9 @@ class CalculateLeadScoresCoverageTest extends BaseTest + /******************************************************************************* + ** Insert Contact With Phone. + *******************************************************************************/ private Integer insertContactWithPhone(String firstName, String lastName, String email, String phone) throws QException { @@ -247,6 +278,9 @@ class CalculateLeadScoresCoverageTest extends BaseTest + /******************************************************************************* + ** Run Scoring. + *******************************************************************************/ private RunProcessOutput runScoring() throws QException { RunProcessInput processInput = new RunProcessInput(); @@ -256,6 +290,9 @@ class CalculateLeadScoresCoverageTest extends BaseTest + /******************************************************************************* + ** Get Contact. + *******************************************************************************/ private Contact getContact(Integer id) throws QException { GetOutput getOutput = new GetAction().execute( diff --git a/src/test/java/com/kingsrook/qbits/crm/scoring/processes/CalculateLeadScoresProcessTest.java b/src/test/java/com/kingsrook/qbits/crm/scoring/processes/CalculateLeadScoresProcessTest.java index 72212f9..6e7415f 100644 --- a/src/test/java/com/kingsrook/qbits/crm/scoring/processes/CalculateLeadScoresProcessTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/scoring/processes/CalculateLeadScoresProcessTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CalculateLeadScoresProcess. *******************************************************************************/ + package com.kingsrook.qbits.crm.scoring.processes; diff --git a/src/test/java/com/kingsrook/qbits/crm/sync/ExternalMappingTest.java b/src/test/java/com/kingsrook/qbits/crm/sync/ExternalMappingTest.java index 8b70b5d..4afcfa2 100644 --- a/src/test/java/com/kingsrook/qbits/crm/sync/ExternalMappingTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/sync/ExternalMappingTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for the ExternalMapping entity. *******************************************************************************/ + package com.kingsrook.qbits.crm.sync; diff --git a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmActivityCountWidgetTest.java b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmActivityCountWidgetTest.java index 76c015b..f293088 100644 --- a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmActivityCountWidgetTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmActivityCountWidgetTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CrmActivityCountWidget. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmActivityFeedWidgetTest.java b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmActivityFeedWidgetTest.java index 1dfd9f2..d39fd3b 100644 --- a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmActivityFeedWidgetTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmActivityFeedWidgetTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CrmActivityFeedWidget. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmAvgDealSizeWidgetTest.java b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmAvgDealSizeWidgetTest.java index f6c0257..38ee364 100644 --- a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmAvgDealSizeWidgetTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmAvgDealSizeWidgetTest.java @@ -1,13 +1,33 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CrmAvgDealSizeRenderer. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; import java.math.BigDecimal; import java.time.LocalDate; -import java.util.List; -import java.util.Map; import com.kingsrook.qbits.crm.BaseTest; import com.kingsrook.qbits.crm.deals.model.Deal; import com.kingsrook.qbits.crm.deals.model.Pipeline; @@ -98,6 +118,9 @@ class CrmAvgDealSizeWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline. + *******************************************************************************/ private Integer insertPipeline(String name) throws QException { InsertOutput output = new InsertAction().execute( @@ -108,6 +131,9 @@ class CrmAvgDealSizeWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline Stage. + *******************************************************************************/ private Integer insertPipelineStage(Integer pipelineId, String name, int sortOrder, boolean isClosedWon, boolean isClosedLost) throws QException { @@ -125,6 +151,9 @@ class CrmAvgDealSizeWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Deal. + *******************************************************************************/ private void insertDeal(String name, Integer pipelineId, Integer stageId, BigDecimal amount, BigDecimal amountInBase) throws QException { diff --git a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmContactTimelineWidgetTest.java b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmContactTimelineWidgetTest.java index 4dd2986..1038c74 100644 --- a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmContactTimelineWidgetTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmContactTimelineWidgetTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CrmContactTimelineWidget. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmDealForecastWidgetTest.java b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmDealForecastWidgetTest.java index 9184322..d33345e 100644 --- a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmDealForecastWidgetTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmDealForecastWidgetTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CrmDealForecastWidget. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmPipelineConversionWidgetTest.java b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmPipelineConversionWidgetTest.java index 09e1340..3f2ba8d 100644 --- a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmPipelineConversionWidgetTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmPipelineConversionWidgetTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CrmPipelineConversionWidget. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -78,6 +100,9 @@ class CrmPipelineConversionWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline. + *******************************************************************************/ private Integer insertPipeline(String name) throws QException { InsertOutput output = new InsertAction().execute( @@ -88,6 +113,9 @@ class CrmPipelineConversionWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline Stage. + *******************************************************************************/ private Integer insertPipelineStage(Integer pipelineId, String name, int sortOrder) throws QException { InsertOutput output = new InsertAction().execute( @@ -102,6 +130,9 @@ class CrmPipelineConversionWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Stage History. + *******************************************************************************/ private void insertStageHistory(Integer dealId, Integer fromStageId, Integer toStageId) throws QException { new InsertAction().execute( diff --git a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmPipelineSummaryWidgetTest.java b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmPipelineSummaryWidgetTest.java index 00e218b..0b5aabc 100644 --- a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmPipelineSummaryWidgetTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmPipelineSummaryWidgetTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CrmPipelineSummaryWidget. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmQuotaAttainmentWidgetTest.java b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmQuotaAttainmentWidgetTest.java index dc5fca8..2a46c6a 100644 --- a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmQuotaAttainmentWidgetTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmQuotaAttainmentWidgetTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CrmQuotaAttainmentRenderer. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -128,6 +150,9 @@ class CrmQuotaAttainmentWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline. + *******************************************************************************/ private Integer insertPipeline(String name) throws QException { InsertOutput output = new InsertAction().execute( @@ -138,6 +163,9 @@ class CrmQuotaAttainmentWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline Stage. + *******************************************************************************/ private Integer insertPipelineStage(Integer pipelineId, String name, int sortOrder, boolean isClosedWon, boolean isClosedLost) throws QException { @@ -155,6 +183,9 @@ class CrmQuotaAttainmentWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Sales Goal. + *******************************************************************************/ private void insertSalesGoal(String userId, Integer pipelineId, BigDecimal target) throws QException { new InsertAction().execute( @@ -171,6 +202,9 @@ class CrmQuotaAttainmentWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Sales Goal No Pipeline. + *******************************************************************************/ private void insertSalesGoalNoPipeline(String userId, BigDecimal target) throws QException { new InsertAction().execute( @@ -186,6 +220,9 @@ class CrmQuotaAttainmentWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Deal. + *******************************************************************************/ private void insertDeal(String name, Integer pipelineId, Integer stageId, BigDecimal amountInBase) throws QException { diff --git a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmRecentDealsWidgetTest.java b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmRecentDealsWidgetTest.java index 7b914a4..3a09414 100644 --- a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmRecentDealsWidgetTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmRecentDealsWidgetTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CrmRecentDealsWidget. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -106,6 +128,9 @@ class CrmRecentDealsWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline. + *******************************************************************************/ private Integer insertPipeline(String name) throws QException { InsertOutput output = new InsertAction().execute( @@ -116,6 +141,9 @@ class CrmRecentDealsWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline Stage. + *******************************************************************************/ private Integer insertPipelineStage(Integer pipelineId, String name, int sortOrder) throws QException { InsertOutput output = new InsertAction().execute( @@ -130,6 +158,9 @@ class CrmRecentDealsWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Closed Deal. + *******************************************************************************/ private void insertClosedDeal(String name, Integer pipelineId, Integer stageId, BigDecimal amount, LocalDate closeDate) throws QException { new InsertAction().execute( diff --git a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmRottingDealsWidgetTest.java b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmRottingDealsWidgetTest.java index e36d1b6..0621b13 100644 --- a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmRottingDealsWidgetTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmRottingDealsWidgetTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CrmRottingDealsWidget. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; diff --git a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmSalesCycleLengthWidgetTest.java b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmSalesCycleLengthWidgetTest.java index efc895d..1329025 100644 --- a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmSalesCycleLengthWidgetTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmSalesCycleLengthWidgetTest.java @@ -1,14 +1,33 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CrmSalesCycleLengthRenderer. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; import java.math.BigDecimal; -import java.time.Instant; import java.time.LocalDate; -import java.util.List; -import java.util.Map; import com.kingsrook.qbits.crm.BaseTest; import com.kingsrook.qbits.crm.deals.model.Deal; import com.kingsrook.qbits.crm.deals.model.Pipeline; @@ -75,6 +94,9 @@ class CrmSalesCycleLengthWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline. + *******************************************************************************/ private Integer insertPipeline(String name) throws QException { InsertOutput output = new InsertAction().execute( @@ -85,6 +107,9 @@ class CrmSalesCycleLengthWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline Stage. + *******************************************************************************/ private Integer insertPipelineStage(Integer pipelineId, String name, int sortOrder, boolean isClosedWon, boolean isClosedLost) throws QException { @@ -102,6 +127,9 @@ class CrmSalesCycleLengthWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Deal. + *******************************************************************************/ private void insertDeal(String name, Integer pipelineId, Integer stageId, LocalDate closeDate) throws QException { diff --git a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmSalesLeaderboardWidgetTest.java b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmSalesLeaderboardWidgetTest.java index fc81b98..286d72e 100644 --- a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmSalesLeaderboardWidgetTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmSalesLeaderboardWidgetTest.java @@ -1,13 +1,33 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CrmSalesLeaderboardRenderer. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; import java.math.BigDecimal; import java.time.LocalDate; -import java.util.List; -import java.util.Map; import com.kingsrook.qbits.crm.BaseTest; import com.kingsrook.qbits.crm.deals.model.Deal; import com.kingsrook.qbits.crm.deals.model.Pipeline; @@ -75,6 +95,9 @@ class CrmSalesLeaderboardWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline. + *******************************************************************************/ private Integer insertPipeline(String name) throws QException { InsertOutput output = new InsertAction().execute( @@ -85,6 +108,9 @@ class CrmSalesLeaderboardWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline Stage. + *******************************************************************************/ private Integer insertPipelineStage(Integer pipelineId, String name, int sortOrder, boolean isClosedWon, boolean isClosedLost) throws QException { @@ -102,6 +128,9 @@ class CrmSalesLeaderboardWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Deal. + *******************************************************************************/ private void insertDeal(String name, Integer pipelineId, Integer stageId, BigDecimal amountInBase, String ownerUserId) throws QException { diff --git a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmStageDurationWidgetTest.java b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmStageDurationWidgetTest.java index 105e26a..1521d43 100644 --- a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmStageDurationWidgetTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmStageDurationWidgetTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CrmStageDurationRenderer. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -110,6 +132,9 @@ class CrmStageDurationWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline. + *******************************************************************************/ private Integer insertPipeline(String name) throws QException { InsertOutput output = new InsertAction().execute( @@ -120,6 +145,9 @@ class CrmStageDurationWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline Stage. + *******************************************************************************/ private Integer insertPipelineStage(Integer pipelineId, String name, int sortOrder) throws QException { InsertOutput output = new InsertAction().execute( @@ -134,6 +162,9 @@ class CrmStageDurationWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Stage History. + *******************************************************************************/ private void insertStageHistory(Integer dealId, Integer fromStageId, Integer toStageId, Integer durationDays) throws QException { new InsertAction().execute( diff --git a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmWinRateWidgetTest.java b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmWinRateWidgetTest.java index fdd1349..f5cea21 100644 --- a/src/test/java/com/kingsrook/qbits/crm/widgets/CrmWinRateWidgetTest.java +++ b/src/test/java/com/kingsrook/qbits/crm/widgets/CrmWinRateWidgetTest.java @@ -1,6 +1,28 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2026. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /******************************************************************************* ** Unit tests for CrmWinRateWidget. *******************************************************************************/ + package com.kingsrook.qbits.crm.widgets; @@ -103,6 +125,9 @@ class CrmWinRateWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline. + *******************************************************************************/ private Integer insertPipeline(String name) throws QException { InsertOutput output = new InsertAction().execute( @@ -113,6 +138,9 @@ class CrmWinRateWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Pipeline Stage. + *******************************************************************************/ private Integer insertPipelineStage(Integer pipelineId, String name, int sortOrder, boolean isClosedWon, boolean isClosedLost) throws QException { InsertOutput output = new InsertAction().execute( @@ -129,6 +157,9 @@ class CrmWinRateWidgetTest extends BaseTest + /******************************************************************************* + ** Insert Stage History. + *******************************************************************************/ private void insertStageHistory(Integer dealId, Integer fromStageId, Integer toStageId) throws QException { new InsertAction().execute(