feat: legal and agreement create actions#15
Conversation
WalkthroughThis change introduces new Vue components for managing and displaying partner legal entities and agreements, including creation forms and modal dialogs. It adds backend API endpoints and repository methods for creating these entities, integrates validation schemas, updates localization for new messages, and refactors the partner page to use the new components, removing inline logic. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant PartnerPage
participant PartnerLegalEntityCard
participant CreatePartnerLegalEntityModal
participant CreatePartnerLegalEntityForm
participant API
participant PartnerStore
User->>PartnerPage: Visits partner page
PartnerPage->>PartnerLegalEntityCard: Renders card
User->>PartnerLegalEntityCard: Clicks "Add Legal Entity"
PartnerLegalEntityCard->>CreatePartnerLegalEntityModal: Opens modal
CreatePartnerLegalEntityModal->>CreatePartnerLegalEntityForm: Renders form
User->>CreatePartnerLegalEntityForm: Submits form
CreatePartnerLegalEntityForm->>API: POST /api/partner/id/{partnerId}/legal
API-->>CreatePartnerLegalEntityForm: Returns created entity
CreatePartnerLegalEntityForm->>PartnerStore: Updates store
CreatePartnerLegalEntityForm->>CreatePartnerLegalEntityModal: Emits success
CreatePartnerLegalEntityModal->>PartnerLegalEntityCard: Closes modal, triggers UI update
sequenceDiagram
participant User
participant PartnerPage
participant PartnerAgreementCard
participant CreatePartnerAgreementModal
participant CreatePartnerAgreementForm
participant API
participant PartnerStore
User->>PartnerPage: Visits partner page
PartnerPage->>PartnerAgreementCard: Renders card
User->>PartnerAgreementCard: Clicks "Add Agreement"
PartnerAgreementCard->>CreatePartnerAgreementModal: Opens modal
CreatePartnerAgreementModal->>CreatePartnerAgreementForm: Renders form
User->>CreatePartnerAgreementForm: Submits form
CreatePartnerAgreementForm->>API: POST /api/partner/id/{partnerId}/agreement
API-->>CreatePartnerAgreementForm: Returns created agreement
CreatePartnerAgreementForm->>PartnerStore: Updates store
CreatePartnerAgreementForm->>CreatePartnerAgreementModal: Emits success
CreatePartnerAgreementModal->>PartnerAgreementCard: Closes modal, triggers UI update
Estimated code review effort🎯 4 (Complex) | ⏱️ ~90 minutes Possibly related PRs
Poem
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 14
🧹 Nitpick comments (8)
apps/web-app/app/components/modal/CreatePartnerAgreement.vue (2)
5-6: Consider using undefined instead of empty strings for missing props.Defaulting optional props to empty strings might cause issues in the form component. Consider passing
undefinedwhen props are not provided:- :partner-id="partnerId ?? ''" - :legal-entity-id="legalEntityId ?? ''" + :partner-id="partnerId" + :legal-entity-id="legalEntityId"
2-2: Consider using i18n for the modal title.The hardcoded Russian title should ideally use internationalization for better maintainability:
- <UModal title="Создание договора"> + <UModal :title="$t('partner.agreement.create.title')">apps/web-app/app/components/modal/CreatePartnerLegalEntity.vue (2)
5-5: Consider using undefined instead of empty string for missing prop.Similar to the agreement modal, defaulting the optional prop to an empty string might cause issues:
- :partner-id="partnerId ?? ''" + :partner-id="partnerId"
2-2: Consider using i18n for the modal title.The hardcoded Russian title should use internationalization:
- <UModal title="Создание юридического лица"> + <UModal :title="$t('partner.legalEntity.create.title')">apps/web-app/app/components/PartnerLegalEntityCard.vue (1)
20-25: Modal integration looks good, but consider i18n for the label.The creation card implementation and modal integration follow the established patterns well. Consider using internationalization for the label:
- label="Добавить юридическое лицо" + :label="$t('partner.legalEntity.add')"apps/web-app/server/api/partner/id/[partnerId]/agreement.post.ts (1)
27-27: Improve error message specificity.The error message "Unable to create" is too generic and doesn't provide enough context.
Apply this diff to make the error message more specific:
- message: 'Unable to create', + message: 'Unable to create partner agreement',apps/web-app/app/components/form/CreatePartnerAgreement.vue (2)
163-166: Improve error handling specificity.The current error handling is generic. Consider providing more specific error messages based on the error type.
} catch (error) { console.error(error) - actionToast.error(toastId) + const errorMessage = error instanceof Error ? error.message : t('error.unknown') + actionToast.error(toastId, errorMessage) }
149-167: Add client-side business rule validation.Consider adding validation for business rules before form submission for better user experience:
- End date should be after conclusion date
- Royalty percentage should be reasonable (0-100%)
- Monetary values should be positive
async function onSubmit(event: FormSubmitEvent<CreatePartnerAgreement>) { + // Business rule validation + if (state.value.concludedAt && state.value.willEndAt) { + const concludedDate = new Date(state.value.concludedAt) + const endDate = new Date(state.value.willEndAt) + if (endDate <= concludedDate) { + actionToast.error(undefined, t('error.agreement.invalidDateRange')) + return + } + } + const toastId = actionToast.start() emit('submitted')
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
apps/web-app/app/components/PartnerAgreementCard.vue(1 hunks)apps/web-app/app/components/PartnerCard.vue(1 hunks)apps/web-app/app/components/PartnerLegalEntityCard.vue(1 hunks)apps/web-app/app/components/form/CreatePartnerAgreement.vue(1 hunks)apps/web-app/app/components/form/CreatePartnerLegalEntity.vue(1 hunks)apps/web-app/app/components/modal/CreatePartnerAgreement.vue(1 hunks)apps/web-app/app/components/modal/CreatePartnerLegalEntity.vue(1 hunks)apps/web-app/app/pages/partner/[id]/index.vue(2 hunks)apps/web-app/i18n/locales/ru-RU.json(2 hunks)apps/web-app/server/api/partner/id/[partnerId]/agreement.post.ts(1 hunks)apps/web-app/server/api/partner/id/[partnerId]/legal.post.ts(1 hunks)apps/web-app/shared/services/partner.ts(1 hunks)packages/database/src/repository/partner.ts(2 hunks)
🧬 Code Graph Analysis (1)
packages/database/src/repository/partner.ts (2)
packages/database/src/types.ts (2)
PartnerLegalEntityDraft(16-16)PartnerAgreementDraft(19-19)packages/database/src/tables.ts (2)
partnerLegalEntities(91-99)partnerAgreements(101-115)
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/database/src/repository/partner.ts (2)
packages/database/src/types.ts (2)
PartnerLegalEntityDraft(16-16)PartnerAgreementDraft(19-19)packages/database/src/tables.ts (2)
partnerLegalEntities(91-99)partnerAgreements(101-115)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (10)
apps/web-app/app/components/PartnerCard.vue (1)
11-11: LGTM! Nice UX enhancement with smooth fade-in effect.The addition of
opacity-0andduration-200creates a smooth fade-in transition for the agreement progress overlay, improving the user experience with consistent hover animations.apps/web-app/app/components/PartnerLegalEntityCard.vue (2)
2-19: LGTM! Clean conditional rendering and comprehensive entity display.The entity information display is well-structured and includes all relevant legal entity details (name, INN, OGRNIP, comment) with appropriate styling.
28-36: Excellent TypeScript typing and component setup.The props definition properly handles nullable states, and the modal management follows the established overlay pattern consistently.
packages/database/src/repository/partner.ts (4)
1-1: LGTM! Necessary type imports added.The additional draft types are properly imported and required for the new repository methods.
4-4: LGTM! Required table imports added.The partnerAgreements and partnerLegalEntities table imports are necessary for the new insert operations.
38-41: LGTM! Clean implementation following established patterns.The
createLegalEntitymethod correctly implements the database insert operation using Drizzle ORM and follows the same pattern as the existingcreatemethod.
43-46: LGTM! Consistent implementation pattern.The
createAgreementmethod follows the same clean pattern ascreateLegalEntityand existing repository methods, maintaining consistency across the codebase.apps/web-app/i18n/locales/ru-RU.json (1)
30-30: LGTM!The localization additions are well-structured and follow the existing naming conventions.
Also applies to: 355-360
apps/web-app/app/pages/partner/[id]/index.vue (1)
3-3: Good refactoring to improve code organization!The extraction of legal entity and agreement display logic into dedicated components enhances maintainability and follows the single responsibility principle.
Also applies to: 45-55
apps/web-app/app/components/form/CreatePartnerLegalEntity.vue (1)
1-101: Well-implemented form component!The component follows Vue 3 best practices with proper form validation, state management, and error handling. The user experience is enhanced with appropriate toast notifications.
| > | ||
| <UPopover> | ||
| <UFormField | ||
| label="Дата заключения" |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Use internationalization consistently for all labels.
Some form labels are hard-coded in Russian while others use i18n. This should be consistent throughout the form.
- label="Дата заключения"
+ :label="$t('partner.agreement.form.concludedAt')"
- label="Дата окончания"
+ :label="$t('partner.agreement.form.willEndAt')"
- <UFormField label="Номер договора (внутренний)" name="internalId">
+ <UFormField :label="$t('partner.agreement.form.internalId')" name="internalId">
- <UFormField label="Роялти, %" name="royalty">
+ <UFormField :label="$t('partner.agreement.form.royalty')" name="royalty">
- <UFormField label="Мин. роялти, руб" name="minRoyaltyPerMonth">
+ <UFormField :label="$t('partner.agreement.form.minRoyalty')" name="minRoyaltyPerMonth">
- <UFormField label="Паушальный взнос, руб" name="lumpSumPayment">
+ <UFormField :label="$t('partner.agreement.form.lumpSumPayment')" name="lumpSumPayment">Also applies to: 30-30, 48-48, 56-56, 66-66, 75-75
🤖 Prompt for AI Agents
In apps/web-app/app/components/form/CreatePartnerAgreement.vue at lines 10, 30,
48, 56, 66, and 75, the form labels are hard-coded in Russian instead of using
the internationalization (i18n) system. Replace these hard-coded label strings
with the appropriate i18n translation keys by using the $t function or
equivalent i18n method to ensure consistent localization across the form.
| > | ||
| <UInput | ||
| :value="selectedConcludedAt ? df.format(selectedConcludedAt.toDate(getLocalTimeZone())) : ''" | ||
| placeholder="Выберите дату" |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Use internationalization for placeholder text.
Placeholder text should also use i18n for consistency.
- placeholder="Выберите дату"
+ :placeholder="$t('common.selectDate')"
- placeholder="Для внутреннего использования"
+ :placeholder="$t('partner.agreement.form.commentPlaceholder')"Also applies to: 36-36, 88-88
🤖 Prompt for AI Agents
In apps/web-app/app/components/form/CreatePartnerAgreement.vue at lines 16, 36,
and 88, the placeholder text is hardcoded in Russian. Replace these hardcoded
placeholder strings with calls to the internationalization (i18n) function to
ensure the text is localized consistently across the app. Use the appropriate
i18n key for each placeholder and update the template bindings accordingly.
| watch(selectedConcludedAt, () => { | ||
| state.value.concludedAt = new Date( | ||
| `${selectedConcludedAt.value?.toString()} 12:00:00`, | ||
| ).toISOString() | ||
| }) | ||
| watch(selectedWillEndAt, () => { | ||
| state.value.willEndAt = new Date( | ||
| `${selectedWillEndAt.value?.toString()} 12:00:00`, | ||
| ).toISOString() | ||
| }) |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Improve date conversion logic for reliability.
The current date conversion logic manually constructs date strings which can be error-prone and fragile. Consider using proper date conversion methods.
watch(selectedConcludedAt, () => {
- state.value.concludedAt = new Date(
- `${selectedConcludedAt.value?.toString()} 12:00:00`,
- ).toISOString()
+ if (selectedConcludedAt.value) {
+ state.value.concludedAt = selectedConcludedAt.value.toDate(getLocalTimeZone()).toISOString()
+ }
})
watch(selectedWillEndAt, () => {
- state.value.willEndAt = new Date(
- `${selectedWillEndAt.value?.toString()} 12:00:00`,
- ).toISOString()
+ if (selectedWillEndAt.value) {
+ state.value.willEndAt = selectedWillEndAt.value.toDate(getLocalTimeZone()).toISOString()
+ }
})Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/web-app/app/components/form/CreatePartnerAgreement.vue around lines 138
to 147, the date conversion manually constructs date strings by appending
"12:00:00" which is fragile and error-prone. Instead, update the watchers to
convert the selected date values to Date objects directly using reliable methods
like setting the time explicitly or using date libraries if available, then
convert to ISO string. This will ensure consistent and accurate date handling.
| <h3 class="text-xl md:text-xl/6 font-semibold"> | ||
| Договор №{{ agreement.internalId }} | ||
| </h3> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Use internationalization for hard-coded Russian text.
Hard-coded Russian text should be moved to i18n locales for better maintainability and potential future localization.
- <h3 class="text-xl md:text-xl/6 font-semibold">
- Договор №{{ agreement.internalId }}
- </h3>
+ <h3 class="text-xl md:text-xl/6 font-semibold">
+ {{ $t('partner.agreement.title', { id: agreement.internalId }) }}
+ </h3>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <h3 class="text-xl md:text-xl/6 font-semibold"> | |
| Договор №{{ agreement.internalId }} | |
| </h3> | |
| <h3 class="text-xl md:text-xl/6 font-semibold"> | |
| {{ $t('partner.agreement.title', { id: agreement.internalId }) }} | |
| </h3> |
🤖 Prompt for AI Agents
In apps/web-app/app/components/PartnerAgreementCard.vue around lines 19 to 21,
the hard-coded Russian text "Договор №" should be replaced with a call to the
internationalization (i18n) system. Move this text to the appropriate i18n
locale file and update the template to use the i18n key instead, ensuring the
text can be localized and maintained properly.
| <p v-if="agreement.concludedAt"> | ||
| Заключен: {{ format(new Date(agreement.concludedAt), 'd MMMM yyyy', { locale: ru }) }} | ||
| </p> | ||
| <p v-if="agreement.willEndAt"> | ||
| Действует до: {{ format(new Date(agreement.willEndAt), 'd MMMM yyyy', { locale: ru }) }} | ||
| </p> | ||
| <p>Роялти: {{ agreement.royalty }}%</p> | ||
| <p>Мин. роялти: {{ agreement.minRoyaltyPerMonth }} ₽ / месяц</p> | ||
|
|
||
| <p v-if="agreement.marketingFee"> | ||
| Маркетинговый сбор: {{ agreement.marketingFee }}% | ||
| </p> | ||
| <p v-if="agreement.minMarketingFeePerMonth"> | ||
| Мин. маркетинговый сбор: {{ agreement.minMarketingFeePerMonth }} ₽ / месяц | ||
| </p> | ||
|
|
||
| <p>Паушальный взнос: {{ agreement.lumpSumPayment }} ₽</p> | ||
| </div> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Use internationalization for hard-coded Russian labels.
All the Russian labels should be extracted to i18n locales for consistency and maintainability.
- <p v-if="agreement.concludedAt">
- Заключен: {{ format(new Date(agreement.concludedAt), 'd MMMM yyyy', { locale: ru }) }}
- </p>
- <p v-if="agreement.willEndAt">
- Действует до: {{ format(new Date(agreement.willEndAt), 'd MMMM yyyy', { locale: ru }) }}
- </p>
- <p>Роялти: {{ agreement.royalty }}%</p>
- <p>Мин. роялти: {{ agreement.minRoyaltyPerMonth }} ₽ / месяц</p>
+ <p v-if="agreement.concludedAt">
+ {{ $t('partner.agreement.concluded') }}: {{ format(new Date(agreement.concludedAt), 'd MMMM yyyy', { locale: ru }) }}
+ </p>
+ <p v-if="agreement.willEndAt">
+ {{ $t('partner.agreement.validUntil') }}: {{ format(new Date(agreement.willEndAt), 'd MMMM yyyy', { locale: ru }) }}
+ </p>
+ <p>{{ $t('partner.agreement.royalty') }}: {{ agreement.royalty }}%</p>
+ <p>{{ $t('partner.agreement.minRoyalty') }}: {{ agreement.minRoyaltyPerMonth }} ₽ / {{ $t('common.month') }}</p>🤖 Prompt for AI Agents
In apps/web-app/app/components/PartnerAgreementCard.vue between lines 24 and 41,
the Russian text labels are hard-coded directly in the template. To fix this,
replace all these hard-coded Russian strings with references to i18n locale keys
using the appropriate translation function or directive. Extract each label into
the i18n locale files to ensure consistency and maintainability across the app.
| import { type } from 'arktype' | ||
|
|
||
| export const createPartnerLegalEntitySchema = type({ | ||
| inn: type('8 <= string <= 16').describe('error.length.invalid'), |
There was a problem hiding this comment.
Fix INN validation to match Russian tax number requirements.
INN (Individual Taxpayer Number) in Russia has specific length requirements: 10 digits for organizations, 12 digits for individuals. The current constraint of 8-16 characters is incorrect.
- inn: type('8 <= string <= 16').describe('error.length.invalid'),
+ inn: type('/^\\d{10}$|^\\d{12}$/').describe('error.inn.invalid'),
- inn: type('8 <= string <= 16 | undefined').describe('error.length.invalid').optional(),
+ inn: type('/^\\d{10}$|^\\d{12}$/ | undefined').describe('error.inn.invalid').optional(),Also applies to: 12-12
🤖 Prompt for AI Agents
In apps/web-app/shared/services/partner.ts at line 4, the INN validation
currently allows strings between 8 and 16 characters, which is incorrect. Update
the validation to only accept strings of length 10 or 12 to match Russian tax
number requirements for organizations and individuals respectively. Adjust the
type or validation logic to enforce these exact lengths instead of a range.
|
|
||
| export const createPartnerLegalEntitySchema = type({ | ||
| inn: type('8 <= string <= 16').describe('error.length.invalid'), | ||
| ogrnip: type('8 <= string <= 25 | undefined').describe('error.length.invalid').optional(), |
There was a problem hiding this comment.
Fix OGRNIP validation to match Russian requirements.
OGRNIP (Primary State Registration Number of Individual Entrepreneur) in Russia must be exactly 15 digits, not 8-25 characters.
- ogrnip: type('8 <= string <= 25 | undefined').describe('error.length.invalid').optional(),
+ ogrnip: type('/^\\d{15}$/ | undefined').describe('error.ogrnip.invalid').optional(),
- ogrnip: type('8 <= string <= 25 | undefined').describe('error.length.invalid').optional(),
+ ogrnip: type('/^\\d{15}$/ | undefined').describe('error.ogrnip.invalid').optional(),Also applies to: 13-13
🤖 Prompt for AI Agents
In apps/web-app/shared/services/partner.ts at line 5, the OGRNIP validation
currently allows strings between 8 and 25 characters, which is incorrect. Update
the validation to require exactly 15 digits for OGRNIP to comply with Russian
standards. Adjust the type or validation schema to enforce a fixed length of 15
characters instead of a range.
| inn: type('8 <= string <= 16').describe('error.length.invalid'), | ||
| ogrnip: type('8 <= string <= 25 | undefined').describe('error.length.invalid').optional(), | ||
| name: type('8 <= string <= 150').describe('error.length.invalid'), | ||
| comment: type('string | undefined').describe('error.length.invalid').optional(), |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Use specific error messages for different field types.
All fields currently use the same generic error message. Different field types should have specific, meaningful error messages.
- comment: type('string | undefined').describe('error.length.invalid').optional(),
+ comment: type('string | undefined').describe('error.comment.invalid').optional(),Apply similar changes to all comment fields and consider adding length constraints:
+ comment: type('0 <= string <= 500 | undefined').describe('error.comment.tooLong').optional(),Also applies to: 15-15, 27-27, 39-39
🤖 Prompt for AI Agents
In apps/web-app/shared/services/partner.ts at lines 7, 15, 27, and 39, the
comment fields use a generic error message for validation. Update each comment
field to use specific error messages tailored to the field type, replacing the
generic 'error.length.invalid' message with more descriptive ones. Additionally,
add appropriate length constraints to these fields to enforce validation rules
clearly.
| concludedAt: type('string').describe('error.length.invalid'), | ||
| willEndAt: type('string').describe('error.length.invalid').optional(), |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add proper date validation for agreement dates.
Date fields should validate ISO string format and ensure business rule compliance.
- concludedAt: type('string').describe('error.length.invalid'),
- willEndAt: type('string').describe('error.length.invalid').optional(),
+ concludedAt: type('/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z$/', 'string').describe('error.date.invalid'),
+ willEndAt: type('/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z$/ | undefined', 'string | undefined').describe('error.date.invalid').optional(),
- concludedAt: type('string | undefined').describe('error.length.invalid').optional(),
- willEndAt: type('string | undefined').describe('error.length.invalid').optional(),
+ concludedAt: type('/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z$/ | undefined', 'string | undefined').describe('error.date.invalid').optional(),
+ willEndAt: type('/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z$/ | undefined', 'string | undefined').describe('error.date.invalid').optional(),Also applies to: 32-33
🤖 Prompt for AI Agents
In apps/web-app/shared/services/partner.ts at lines 20-21 and 32-33, the date
fields concludedAt and willEndAt currently only validate as strings without
enforcing ISO date format or business rules. Replace the simple string type
validation with a date validation that checks for ISO 8601 format compliance.
Additionally, implement any necessary business rule validations such as ensuring
concludedAt is before willEndAt or other domain-specific constraints. Use a date
validation library or custom validation logic to enforce these rules.
| royalty: type('number').describe('error.length.invalid'), | ||
| minRoyaltyPerMonth: type('number').describe('error.length.invalid'), | ||
| lumpSumPayment: type('number').describe('error.length.invalid'), |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add reasonable range validation for numerical fields.
Percentage and monetary fields should have reasonable bounds to prevent invalid business data.
- royalty: type('number').describe('error.length.invalid'),
- minRoyaltyPerMonth: type('number').describe('error.length.invalid'),
- lumpSumPayment: type('number').describe('error.length.invalid'),
+ royalty: type('0 <= number <= 100').describe('error.percentage.invalid'),
+ minRoyaltyPerMonth: type('number >= 0').describe('error.amount.invalid'),
+ lumpSumPayment: type('number >= 0').describe('error.amount.invalid'),
- royalty: type('number | undefined').describe('error.length.invalid').optional(),
- minRoyaltyPerMonth: type('number | undefined').describe('error.length.invalid').optional(),
- lumpSumPayment: type('number | undefined').describe('error.length.invalid').optional(),
+ royalty: type('0 <= number <= 100 | undefined').describe('error.percentage.invalid').optional(),
+ minRoyaltyPerMonth: type('number >= 0 | undefined').describe('error.amount.invalid').optional(),
+ lumpSumPayment: type('number >= 0 | undefined').describe('error.amount.invalid').optional(),Also applies to: 35-37
🤖 Prompt for AI Agents
In apps/web-app/shared/services/partner.ts around lines 23 to 25 and 35 to 37,
the numerical fields royalty, minRoyaltyPerMonth, and lumpSumPayment currently
only have type validation without range checks. Add reasonable minimum and
maximum value validations to these fields to ensure the values fall within
acceptable business limits, such as percentages between 0 and 100 or monetary
amounts above zero, by extending the schema definitions with range constraints.
|



Summary by CodeRabbit
New Features
Enhancements
Bug Fixes
Documentation
Chores