@hed-hog/contact 0.0.300 → 0.0.302
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/contact.module.d.ts.map +1 -1
- package/dist/contact.module.js +2 -0
- package/dist/contact.module.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/person/person.service.d.ts +2 -0
- package/dist/person/person.service.d.ts.map +1 -1
- package/dist/person/person.service.js +111 -127
- package/dist/person/person.service.js.map +1 -1
- package/dist/person/person.service.spec.d.ts +2 -0
- package/dist/person/person.service.spec.d.ts.map +1 -0
- package/dist/person/person.service.spec.js +106 -0
- package/dist/person/person.service.spec.js.map +1 -0
- package/dist/proposal/dto/proposal.dto.d.ts +152 -0
- package/dist/proposal/dto/proposal.dto.d.ts.map +1 -0
- package/dist/proposal/dto/proposal.dto.js +396 -0
- package/dist/proposal/dto/proposal.dto.js.map +1 -0
- package/dist/proposal/proposal-contract.subscriber.d.ts +11 -0
- package/dist/proposal/proposal-contract.subscriber.d.ts.map +1 -0
- package/dist/proposal/proposal-contract.subscriber.js +51 -0
- package/dist/proposal/proposal-contract.subscriber.js.map +1 -0
- package/dist/proposal/proposal-event.types.d.ts +122 -0
- package/dist/proposal/proposal-event.types.d.ts.map +1 -0
- package/dist/proposal/proposal-event.types.js +13 -0
- package/dist/proposal/proposal-event.types.js.map +1 -0
- package/dist/proposal/proposal.controller.d.ts +56 -0
- package/dist/proposal/proposal.controller.d.ts.map +1 -0
- package/dist/proposal/proposal.controller.js +191 -0
- package/dist/proposal/proposal.controller.js.map +1 -0
- package/dist/proposal/proposal.module.d.ts +3 -0
- package/dist/proposal/proposal.module.d.ts.map +1 -0
- package/dist/proposal/proposal.module.js +32 -0
- package/dist/proposal/proposal.module.js.map +1 -0
- package/dist/proposal/proposal.service.d.ts +100 -0
- package/dist/proposal/proposal.service.d.ts.map +1 -0
- package/dist/proposal/proposal.service.js +2137 -0
- package/dist/proposal/proposal.service.js.map +1 -0
- package/dist/proposal/proposal.service.spec.d.ts +2 -0
- package/dist/proposal/proposal.service.spec.d.ts.map +1 -0
- package/dist/proposal/proposal.service.spec.js +175 -0
- package/dist/proposal/proposal.service.spec.js.map +1 -0
- package/hedhog/data/menu.yaml +35 -18
- package/hedhog/data/route.yaml +44 -0
- package/hedhog/frontend/app/accounts/_components/account-form-sheet.tsx.ejs +517 -346
- package/hedhog/frontend/app/activities/_components/activity-detail-sheet.tsx.ejs +42 -17
- package/hedhog/frontend/app/activities/_components/activity-types.ts.ejs +1 -1
- package/hedhog/frontend/app/activities/page.tsx.ejs +315 -101
- package/hedhog/frontend/app/follow-ups/page.tsx.ejs +172 -22
- package/hedhog/frontend/app/page.tsx.ejs +1 -1
- package/hedhog/frontend/app/person/_components/person-form-sheet.tsx.ejs +1 -1
- package/hedhog/frontend/app/pipeline/_components/lead-detail-sheet.tsx.ejs +253 -210
- package/hedhog/frontend/app/pipeline/_components/lead-proposals-tab.tsx.ejs +1661 -0
- package/hedhog/frontend/app/pipeline/page.tsx.ejs +30 -4
- package/hedhog/frontend/app/proposals/_components/proposals-management-page.tsx.ejs +773 -0
- package/hedhog/frontend/app/proposals/approvals/page.tsx.ejs +5 -0
- package/hedhog/frontend/app/proposals/page.tsx.ejs +5 -0
- package/hedhog/frontend/app/reports/page.tsx.ejs +431 -375
- package/hedhog/frontend/messages/en.json +236 -43
- package/hedhog/frontend/messages/pt.json +235 -42
- package/hedhog/table/proposal.yaml +112 -0
- package/hedhog/table/proposal_approval.yaml +63 -0
- package/hedhog/table/proposal_document.yaml +77 -0
- package/hedhog/table/proposal_item.yaml +64 -0
- package/hedhog/table/proposal_revision.yaml +78 -0
- package/package.json +5 -4
- package/src/contact.module.ts +2 -0
- package/src/index.ts +3 -0
- package/src/person/person.service.spec.ts +143 -0
- package/src/person/person.service.ts +147 -158
- package/src/proposal/dto/proposal.dto.ts +341 -0
- package/src/proposal/proposal-contract.subscriber.ts +43 -0
- package/src/proposal/proposal-event.types.ts +130 -0
- package/src/proposal/proposal.controller.ts +168 -0
- package/src/proposal/proposal.module.ts +19 -0
- package/src/proposal/proposal.service.spec.ts +196 -0
- package/src/proposal/proposal.service.ts +2855 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
columns:
|
|
2
|
+
- type: pk
|
|
3
|
+
- name: person_id
|
|
4
|
+
type: fk
|
|
5
|
+
references:
|
|
6
|
+
table: person
|
|
7
|
+
column: id
|
|
8
|
+
onDelete: CASCADE
|
|
9
|
+
onUpdate: CASCADE
|
|
10
|
+
- name: code
|
|
11
|
+
type: varchar
|
|
12
|
+
length: 40
|
|
13
|
+
- name: title
|
|
14
|
+
type: varchar
|
|
15
|
+
length: 180
|
|
16
|
+
- name: status
|
|
17
|
+
type: enum
|
|
18
|
+
values: [draft, pending_approval, approved, rejected, cancelled, expired, contract_generated]
|
|
19
|
+
default: draft
|
|
20
|
+
- name: contract_category
|
|
21
|
+
type: enum
|
|
22
|
+
values: [employee, contractor, client, supplier, vendor, partner, internal, other]
|
|
23
|
+
default: client
|
|
24
|
+
- name: contract_type
|
|
25
|
+
type: enum
|
|
26
|
+
values: [clt, pj, freelancer_agreement, service_agreement, fixed_term, recurring_service, nda, amendment, addendum, other]
|
|
27
|
+
default: service_agreement
|
|
28
|
+
- name: billing_model
|
|
29
|
+
type: enum
|
|
30
|
+
values: [time_and_material, monthly_retainer, fixed_price]
|
|
31
|
+
default: fixed_price
|
|
32
|
+
- name: currency_code
|
|
33
|
+
type: varchar
|
|
34
|
+
length: 8
|
|
35
|
+
default: BRL
|
|
36
|
+
- name: valid_from
|
|
37
|
+
type: datetime
|
|
38
|
+
isNullable: true
|
|
39
|
+
- name: valid_until
|
|
40
|
+
type: datetime
|
|
41
|
+
isNullable: true
|
|
42
|
+
- name: subtotal_amount_cents
|
|
43
|
+
type: int
|
|
44
|
+
default: 0
|
|
45
|
+
- name: discount_amount_cents
|
|
46
|
+
type: int
|
|
47
|
+
default: 0
|
|
48
|
+
- name: tax_amount_cents
|
|
49
|
+
type: int
|
|
50
|
+
default: 0
|
|
51
|
+
- name: total_amount_cents
|
|
52
|
+
type: int
|
|
53
|
+
default: 0
|
|
54
|
+
- name: notes
|
|
55
|
+
type: text
|
|
56
|
+
isNullable: true
|
|
57
|
+
- name: owner_user_id
|
|
58
|
+
type: fk
|
|
59
|
+
isNullable: true
|
|
60
|
+
references:
|
|
61
|
+
table: user
|
|
62
|
+
column: id
|
|
63
|
+
onDelete: SET NULL
|
|
64
|
+
onUpdate: CASCADE
|
|
65
|
+
- name: created_by_user_id
|
|
66
|
+
type: fk
|
|
67
|
+
isNullable: true
|
|
68
|
+
references:
|
|
69
|
+
table: user
|
|
70
|
+
column: id
|
|
71
|
+
onDelete: SET NULL
|
|
72
|
+
onUpdate: CASCADE
|
|
73
|
+
- name: updated_by_user_id
|
|
74
|
+
type: fk
|
|
75
|
+
isNullable: true
|
|
76
|
+
references:
|
|
77
|
+
table: user
|
|
78
|
+
column: id
|
|
79
|
+
onDelete: SET NULL
|
|
80
|
+
onUpdate: CASCADE
|
|
81
|
+
- name: approved_by_user_id
|
|
82
|
+
type: fk
|
|
83
|
+
isNullable: true
|
|
84
|
+
references:
|
|
85
|
+
table: user
|
|
86
|
+
column: id
|
|
87
|
+
onDelete: SET NULL
|
|
88
|
+
onUpdate: CASCADE
|
|
89
|
+
- name: approved_at
|
|
90
|
+
type: datetime
|
|
91
|
+
isNullable: true
|
|
92
|
+
- name: contract_generated_at
|
|
93
|
+
type: datetime
|
|
94
|
+
isNullable: true
|
|
95
|
+
- name: current_revision_number
|
|
96
|
+
type: int
|
|
97
|
+
default: 0
|
|
98
|
+
- name: deleted_at
|
|
99
|
+
type: datetime
|
|
100
|
+
isNullable: true
|
|
101
|
+
- type: created_at
|
|
102
|
+
- type: updated_at
|
|
103
|
+
|
|
104
|
+
indices:
|
|
105
|
+
- columns: [code]
|
|
106
|
+
isUnique: true
|
|
107
|
+
- columns: [person_id]
|
|
108
|
+
- columns: [person_id, status]
|
|
109
|
+
- columns: [status]
|
|
110
|
+
- columns: [valid_until]
|
|
111
|
+
- columns: [approved_at]
|
|
112
|
+
- columns: [deleted_at]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
columns:
|
|
2
|
+
- type: pk
|
|
3
|
+
- name: proposal_id
|
|
4
|
+
type: fk
|
|
5
|
+
references:
|
|
6
|
+
table: proposal
|
|
7
|
+
column: id
|
|
8
|
+
onDelete: CASCADE
|
|
9
|
+
onUpdate: CASCADE
|
|
10
|
+
- name: proposal_revision_id
|
|
11
|
+
type: fk
|
|
12
|
+
references:
|
|
13
|
+
table: proposal_revision
|
|
14
|
+
column: id
|
|
15
|
+
onDelete: CASCADE
|
|
16
|
+
onUpdate: CASCADE
|
|
17
|
+
- name: requester_user_id
|
|
18
|
+
type: fk
|
|
19
|
+
isNullable: true
|
|
20
|
+
references:
|
|
21
|
+
table: user
|
|
22
|
+
column: id
|
|
23
|
+
onDelete: SET NULL
|
|
24
|
+
onUpdate: CASCADE
|
|
25
|
+
- name: approver_user_id
|
|
26
|
+
type: fk
|
|
27
|
+
isNullable: true
|
|
28
|
+
references:
|
|
29
|
+
table: user
|
|
30
|
+
column: id
|
|
31
|
+
onDelete: SET NULL
|
|
32
|
+
onUpdate: CASCADE
|
|
33
|
+
- name: step_order
|
|
34
|
+
type: int
|
|
35
|
+
default: 1
|
|
36
|
+
- name: status
|
|
37
|
+
type: enum
|
|
38
|
+
values: [pending, approved, rejected, cancelled]
|
|
39
|
+
default: pending
|
|
40
|
+
- name: submitted_at
|
|
41
|
+
type: datetime
|
|
42
|
+
- name: decided_at
|
|
43
|
+
type: datetime
|
|
44
|
+
isNullable: true
|
|
45
|
+
- name: decision_note
|
|
46
|
+
type: text
|
|
47
|
+
isNullable: true
|
|
48
|
+
- name: deleted_at
|
|
49
|
+
type: datetime
|
|
50
|
+
isNullable: true
|
|
51
|
+
- type: created_at
|
|
52
|
+
- type: updated_at
|
|
53
|
+
|
|
54
|
+
indices:
|
|
55
|
+
- columns: [proposal_id]
|
|
56
|
+
- columns: [proposal_revision_id, step_order]
|
|
57
|
+
isUnique: true
|
|
58
|
+
- columns: [requester_user_id]
|
|
59
|
+
- columns: [approver_user_id]
|
|
60
|
+
- columns: [status]
|
|
61
|
+
- columns: [submitted_at]
|
|
62
|
+
- columns: [decided_at]
|
|
63
|
+
- columns: [deleted_at]
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
columns:
|
|
2
|
+
- type: pk
|
|
3
|
+
- name: proposal_id
|
|
4
|
+
type: fk
|
|
5
|
+
references:
|
|
6
|
+
table: proposal
|
|
7
|
+
column: id
|
|
8
|
+
onDelete: CASCADE
|
|
9
|
+
onUpdate: CASCADE
|
|
10
|
+
- name: proposal_revision_id
|
|
11
|
+
type: fk
|
|
12
|
+
isNullable: true
|
|
13
|
+
references:
|
|
14
|
+
table: proposal_revision
|
|
15
|
+
column: id
|
|
16
|
+
onDelete: SET NULL
|
|
17
|
+
onUpdate: CASCADE
|
|
18
|
+
- name: document_type
|
|
19
|
+
type: enum
|
|
20
|
+
values: [source_upload, generated_pdf, approval_attachment, signed_copy, attachment, other]
|
|
21
|
+
default: attachment
|
|
22
|
+
- name: file_id
|
|
23
|
+
type: fk
|
|
24
|
+
isNullable: true
|
|
25
|
+
references:
|
|
26
|
+
table: file
|
|
27
|
+
column: id
|
|
28
|
+
onDelete: SET NULL
|
|
29
|
+
onUpdate: CASCADE
|
|
30
|
+
- name: file_name
|
|
31
|
+
type: varchar
|
|
32
|
+
length: 200
|
|
33
|
+
- name: mime_type
|
|
34
|
+
type: varchar
|
|
35
|
+
length: 120
|
|
36
|
+
- name: file_content_base64
|
|
37
|
+
type: text
|
|
38
|
+
isNullable: true
|
|
39
|
+
- name: is_current
|
|
40
|
+
type: boolean
|
|
41
|
+
default: true
|
|
42
|
+
- name: source_kind
|
|
43
|
+
type: enum
|
|
44
|
+
values: [manual, generated, imported, ai_assisted]
|
|
45
|
+
default: manual
|
|
46
|
+
- name: extraction_status
|
|
47
|
+
type: enum
|
|
48
|
+
values: [pending, processing, completed, failed, skipped]
|
|
49
|
+
default: skipped
|
|
50
|
+
- name: extraction_summary
|
|
51
|
+
type: text
|
|
52
|
+
isNullable: true
|
|
53
|
+
- name: notes
|
|
54
|
+
type: text
|
|
55
|
+
isNullable: true
|
|
56
|
+
- name: uploaded_by_user_id
|
|
57
|
+
type: fk
|
|
58
|
+
isNullable: true
|
|
59
|
+
references:
|
|
60
|
+
table: user
|
|
61
|
+
column: id
|
|
62
|
+
onDelete: SET NULL
|
|
63
|
+
onUpdate: CASCADE
|
|
64
|
+
- name: deleted_at
|
|
65
|
+
type: datetime
|
|
66
|
+
isNullable: true
|
|
67
|
+
- type: created_at
|
|
68
|
+
- type: updated_at
|
|
69
|
+
|
|
70
|
+
indices:
|
|
71
|
+
- columns: [proposal_id]
|
|
72
|
+
- columns: [proposal_revision_id]
|
|
73
|
+
- columns: [document_type]
|
|
74
|
+
- columns: [file_id]
|
|
75
|
+
- columns: [is_current]
|
|
76
|
+
- columns: [extraction_status]
|
|
77
|
+
- columns: [deleted_at]
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
columns:
|
|
2
|
+
- type: pk
|
|
3
|
+
- name: proposal_revision_id
|
|
4
|
+
type: fk
|
|
5
|
+
references:
|
|
6
|
+
table: proposal_revision
|
|
7
|
+
column: id
|
|
8
|
+
onDelete: CASCADE
|
|
9
|
+
onUpdate: CASCADE
|
|
10
|
+
- type: order
|
|
11
|
+
- name: item_type
|
|
12
|
+
type: enum
|
|
13
|
+
values: [service, product, fee, discount, note, other]
|
|
14
|
+
default: service
|
|
15
|
+
- name: term_type
|
|
16
|
+
type: enum
|
|
17
|
+
values: [value, payment, revenue, fine, other]
|
|
18
|
+
default: value
|
|
19
|
+
- name: name
|
|
20
|
+
type: varchar
|
|
21
|
+
length: 180
|
|
22
|
+
- name: description
|
|
23
|
+
type: text
|
|
24
|
+
isNullable: true
|
|
25
|
+
- name: quantity
|
|
26
|
+
type: decimal
|
|
27
|
+
precision: 12
|
|
28
|
+
scale: 2
|
|
29
|
+
default: 1
|
|
30
|
+
- name: unit_amount_cents
|
|
31
|
+
type: int
|
|
32
|
+
default: 0
|
|
33
|
+
- name: total_amount_cents
|
|
34
|
+
type: int
|
|
35
|
+
default: 0
|
|
36
|
+
- name: recurrence
|
|
37
|
+
type: enum
|
|
38
|
+
values: [one_time, monthly, quarterly, yearly, other]
|
|
39
|
+
default: one_time
|
|
40
|
+
- name: due_day
|
|
41
|
+
type: int
|
|
42
|
+
isNullable: true
|
|
43
|
+
- name: start_date
|
|
44
|
+
type: date
|
|
45
|
+
isNullable: true
|
|
46
|
+
- name: end_date
|
|
47
|
+
type: date
|
|
48
|
+
isNullable: true
|
|
49
|
+
- name: metadata_json
|
|
50
|
+
type: json
|
|
51
|
+
isNullable: true
|
|
52
|
+
- name: deleted_at
|
|
53
|
+
type: datetime
|
|
54
|
+
isNullable: true
|
|
55
|
+
- type: created_at
|
|
56
|
+
- type: updated_at
|
|
57
|
+
|
|
58
|
+
indices:
|
|
59
|
+
- columns: [proposal_revision_id]
|
|
60
|
+
- columns: [proposal_revision_id, order]
|
|
61
|
+
- columns: [item_type]
|
|
62
|
+
- columns: [term_type]
|
|
63
|
+
- columns: [recurrence]
|
|
64
|
+
- columns: [deleted_at]
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
columns:
|
|
2
|
+
- type: pk
|
|
3
|
+
- name: proposal_id
|
|
4
|
+
type: fk
|
|
5
|
+
references:
|
|
6
|
+
table: proposal
|
|
7
|
+
column: id
|
|
8
|
+
onDelete: CASCADE
|
|
9
|
+
onUpdate: CASCADE
|
|
10
|
+
- name: revision_number
|
|
11
|
+
type: int
|
|
12
|
+
- name: status
|
|
13
|
+
type: enum
|
|
14
|
+
values: [draft, pending_approval, approved, rejected, cancelled, superseded]
|
|
15
|
+
default: draft
|
|
16
|
+
- name: generation_mode
|
|
17
|
+
type: enum
|
|
18
|
+
values: [manual, ai_assisted, duplicated, imported]
|
|
19
|
+
default: manual
|
|
20
|
+
- name: title
|
|
21
|
+
type: varchar
|
|
22
|
+
length: 180
|
|
23
|
+
- name: summary
|
|
24
|
+
type: text
|
|
25
|
+
isNullable: true
|
|
26
|
+
- name: content_html
|
|
27
|
+
type: text
|
|
28
|
+
isNullable: true
|
|
29
|
+
- name: snapshot_json
|
|
30
|
+
type: json
|
|
31
|
+
isNullable: true
|
|
32
|
+
- name: valid_until
|
|
33
|
+
type: datetime
|
|
34
|
+
isNullable: true
|
|
35
|
+
- name: subtotal_amount_cents
|
|
36
|
+
type: int
|
|
37
|
+
default: 0
|
|
38
|
+
- name: discount_amount_cents
|
|
39
|
+
type: int
|
|
40
|
+
default: 0
|
|
41
|
+
- name: tax_amount_cents
|
|
42
|
+
type: int
|
|
43
|
+
default: 0
|
|
44
|
+
- name: total_amount_cents
|
|
45
|
+
type: int
|
|
46
|
+
default: 0
|
|
47
|
+
- name: submitted_at
|
|
48
|
+
type: datetime
|
|
49
|
+
isNullable: true
|
|
50
|
+
- name: approved_at
|
|
51
|
+
type: datetime
|
|
52
|
+
isNullable: true
|
|
53
|
+
- name: is_current
|
|
54
|
+
type: boolean
|
|
55
|
+
default: true
|
|
56
|
+
- name: created_by_user_id
|
|
57
|
+
type: fk
|
|
58
|
+
isNullable: true
|
|
59
|
+
references:
|
|
60
|
+
table: user
|
|
61
|
+
column: id
|
|
62
|
+
onDelete: SET NULL
|
|
63
|
+
onUpdate: CASCADE
|
|
64
|
+
- name: deleted_at
|
|
65
|
+
type: datetime
|
|
66
|
+
isNullable: true
|
|
67
|
+
- type: created_at
|
|
68
|
+
- type: updated_at
|
|
69
|
+
|
|
70
|
+
indices:
|
|
71
|
+
- columns: [proposal_id, revision_number]
|
|
72
|
+
isUnique: true
|
|
73
|
+
- columns: [proposal_id]
|
|
74
|
+
- columns: [proposal_id, is_current]
|
|
75
|
+
- columns: [status]
|
|
76
|
+
- columns: [submitted_at]
|
|
77
|
+
- columns: [approved_at]
|
|
78
|
+
- columns: [deleted_at]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hed-hog/contact",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.302",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
"@nestjs/core": "^11",
|
|
10
10
|
"@nestjs/jwt": "^11",
|
|
11
11
|
"@nestjs/mapped-types": "*",
|
|
12
|
-
"@hed-hog/
|
|
12
|
+
"@hed-hog/api-prisma": "0.0.6",
|
|
13
13
|
"@hed-hog/api-locale": "0.0.14",
|
|
14
14
|
"@hed-hog/api-mail": "0.0.9",
|
|
15
|
-
"@hed-hog/
|
|
15
|
+
"@hed-hog/core": "0.0.302",
|
|
16
|
+
"@hed-hog/address": "0.0.302",
|
|
16
17
|
"@hed-hog/api": "0.0.6",
|
|
17
|
-
"@hed-hog/address": "0.0.300",
|
|
18
18
|
"@hed-hog/api-pagination": "0.0.7"
|
|
19
19
|
},
|
|
20
20
|
"exports": {
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
],
|
|
32
32
|
"scripts": {
|
|
33
33
|
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\"",
|
|
34
|
+
"test": "jest --config jest.config.ts --runInBand",
|
|
34
35
|
"prebuild": "pnpm --dir ../.. exec ts-node ./scripts/build-dependencies.ts libraries/contact",
|
|
35
36
|
"build": "tsc --project tsconfig.production.json",
|
|
36
37
|
"patch": "npx ts-node ../../scripts/patch.ts libraries/contact",
|
package/src/contact.module.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { ContactService } from './contact.service';
|
|
|
11
11
|
import { PersonDocumentTypeModule } from './document-type/document-type.module';
|
|
12
12
|
import { PersonRelationTypeModule } from './person-relation-type/person-relation-type.module';
|
|
13
13
|
import { PersonModule } from './person/person.module';
|
|
14
|
+
import { ProposalModule } from './proposal/proposal.module';
|
|
14
15
|
|
|
15
16
|
@Module({
|
|
16
17
|
imports: [
|
|
@@ -33,6 +34,7 @@ import { PersonModule } from './person/person.module';
|
|
|
33
34
|
forwardRef(() => PrismaModule),
|
|
34
35
|
forwardRef(() => PaginationModule),
|
|
35
36
|
forwardRef(() => PersonModule),
|
|
37
|
+
forwardRef(() => ProposalModule),
|
|
36
38
|
forwardRef(() => PersonContactTypeModule),
|
|
37
39
|
forwardRef(() => PersonDocumentTypeModule),
|
|
38
40
|
forwardRef(() => PersonRelationTypeModule),
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export * from './contact.module';
|
|
2
2
|
export * from './contact.service';
|
|
3
|
+
export * from './proposal/proposal-event.types';
|
|
4
|
+
export * from './proposal/proposal.module';
|
|
5
|
+
export * from './proposal/proposal.service';
|
|
3
6
|
|
|
4
7
|
export * from './address-type.enum';
|
|
5
8
|
export * from './contact-type/contact-type.enum';
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/// <reference types="jest" />
|
|
2
|
+
import { PersonInteractionTypeDTO } from './dto/create-interaction.dto';
|
|
3
|
+
import { PersonService } from './person.service';
|
|
4
|
+
|
|
5
|
+
describe('PersonService CRM interaction/follow-up regression coverage', () => {
|
|
6
|
+
let prisma: any;
|
|
7
|
+
let tx: any;
|
|
8
|
+
let service: PersonService;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
tx = {
|
|
12
|
+
crm_activity: {
|
|
13
|
+
findFirst: jest.fn().mockResolvedValue(null),
|
|
14
|
+
create: jest.fn().mockResolvedValue({ id: 1 }),
|
|
15
|
+
update: jest.fn().mockResolvedValue({ id: 1 }),
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
prisma = {
|
|
20
|
+
$transaction: jest.fn().mockImplementation(async (callback: any) =>
|
|
21
|
+
callback(tx)
|
|
22
|
+
),
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
service = new PersonService(
|
|
26
|
+
prisma as any,
|
|
27
|
+
{} as any,
|
|
28
|
+
{} as any,
|
|
29
|
+
{
|
|
30
|
+
getSettingValues: jest.fn().mockResolvedValue({}),
|
|
31
|
+
} as any
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
jest
|
|
35
|
+
.spyOn(service as any, 'ensurePersonAccessible')
|
|
36
|
+
.mockResolvedValue({ id: 42, type: 'individual', status: 'active' });
|
|
37
|
+
jest.spyOn(service as any, 'getPersonOwnerUserId').mockResolvedValue(7);
|
|
38
|
+
jest.spyOn(service as any, 'loadInteractionsFromTx').mockResolvedValue([]);
|
|
39
|
+
jest.spyOn(service as any, 'upsertMetadataValue').mockResolvedValue(undefined);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('persists a completed crm activity when registering an interaction', async () => {
|
|
43
|
+
await service.createInteraction(
|
|
44
|
+
42,
|
|
45
|
+
{
|
|
46
|
+
type: PersonInteractionTypeDTO.CALL,
|
|
47
|
+
notes: 'Ligação inicial',
|
|
48
|
+
},
|
|
49
|
+
'en',
|
|
50
|
+
{ id: 9, name: 'Root User' }
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
expect(tx.crm_activity.create).toHaveBeenCalledWith(
|
|
54
|
+
expect.objectContaining({
|
|
55
|
+
data: expect.objectContaining({
|
|
56
|
+
person_id: 42,
|
|
57
|
+
owner_user_id: 7,
|
|
58
|
+
created_by_user_id: 9,
|
|
59
|
+
completed_by_user_id: 9,
|
|
60
|
+
type: PersonInteractionTypeDTO.CALL,
|
|
61
|
+
subject: 'Call',
|
|
62
|
+
notes: 'Ligação inicial',
|
|
63
|
+
priority: 'medium',
|
|
64
|
+
source_kind: 'interaction',
|
|
65
|
+
due_at: expect.any(Date),
|
|
66
|
+
completed_at: expect.any(Date),
|
|
67
|
+
created_at: expect.any(Date),
|
|
68
|
+
updated_at: expect.any(Date),
|
|
69
|
+
}),
|
|
70
|
+
})
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('creates an open follow-up activity when none exists', async () => {
|
|
75
|
+
tx.crm_activity.findFirst.mockResolvedValue(null);
|
|
76
|
+
|
|
77
|
+
await service.scheduleFollowup(
|
|
78
|
+
42,
|
|
79
|
+
{
|
|
80
|
+
next_action_at: '2026-04-09T13:48:31.715Z',
|
|
81
|
+
notes: 'Retornar por telefone',
|
|
82
|
+
},
|
|
83
|
+
'en',
|
|
84
|
+
{ id: 9, name: 'Root User' }
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
expect(tx.crm_activity.findFirst).toHaveBeenCalledWith({
|
|
88
|
+
where: {
|
|
89
|
+
person_id: 42,
|
|
90
|
+
source_kind: 'followup',
|
|
91
|
+
completed_at: null,
|
|
92
|
+
},
|
|
93
|
+
orderBy: {
|
|
94
|
+
id: 'desc',
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
expect(tx.crm_activity.create).toHaveBeenCalledWith(
|
|
99
|
+
expect.objectContaining({
|
|
100
|
+
data: expect.objectContaining({
|
|
101
|
+
person_id: 42,
|
|
102
|
+
owner_user_id: 7,
|
|
103
|
+
created_by_user_id: 9,
|
|
104
|
+
type: 'task',
|
|
105
|
+
subject: 'Follow-up',
|
|
106
|
+
notes: 'Retornar por telefone',
|
|
107
|
+
priority: 'medium',
|
|
108
|
+
source_kind: 'followup',
|
|
109
|
+
due_at: new Date('2026-04-09T13:48:31.715Z'),
|
|
110
|
+
}),
|
|
111
|
+
})
|
|
112
|
+
);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('updates the existing open follow-up activity when rescheduling', async () => {
|
|
116
|
+
tx.crm_activity.findFirst.mockResolvedValue({ id: 88 });
|
|
117
|
+
|
|
118
|
+
await service.scheduleFollowup(
|
|
119
|
+
42,
|
|
120
|
+
{
|
|
121
|
+
next_action_at: '2026-04-10T15:00:00.000Z',
|
|
122
|
+
notes: 'Reagendar reunião',
|
|
123
|
+
},
|
|
124
|
+
'en',
|
|
125
|
+
{ id: 11, name: 'Owner User' }
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
expect(tx.crm_activity.update).toHaveBeenCalledWith({
|
|
129
|
+
where: {
|
|
130
|
+
id: 88,
|
|
131
|
+
},
|
|
132
|
+
data: expect.objectContaining({
|
|
133
|
+
owner_user_id: 7,
|
|
134
|
+
type: 'task',
|
|
135
|
+
subject: 'Follow-up',
|
|
136
|
+
notes: 'Reagendar reunião',
|
|
137
|
+
due_at: new Date('2026-04-10T15:00:00.000Z'),
|
|
138
|
+
priority: 'medium',
|
|
139
|
+
updated_at: expect.any(Date),
|
|
140
|
+
}),
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
});
|