@@ -303,24 +303,28 @@ function validateBenefitStructure(benefit: PromoCodeBenefit): void {
303303 if ( ! benefit . planId ) {
304304 throw new PromoCodeError ( PromoCodeErrorCode . Invalid , 'Grant plan id is missing' ) ;
305305 }
306+
306307 return ;
307308
308309 case 'percent_discount' :
309310 if ( typeof benefit . percent !== 'number' || benefit . percent <= 0 || benefit . percent > 100 ) {
310311 throw new PromoCodeError ( PromoCodeErrorCode . Invalid , 'Percent discount is invalid' ) ;
311312 }
313+
312314 return ;
313315
314316 case 'amount_discount' :
315317 if ( typeof benefit . amount !== 'number' || benefit . amount <= 0 ) {
316318 throw new PromoCodeError ( PromoCodeErrorCode . Invalid , 'Amount discount is invalid' ) ;
317319 }
320+
318321 return ;
319322
320323 case 'fixed_price' :
321324 if ( typeof benefit . amount !== 'number' || benefit . amount < DEFAULT_MIN_FINAL_PRICE ) {
322325 throw new PromoCodeError ( PromoCodeErrorCode . Invalid , 'Fixed price is invalid' ) ;
323326 }
327+
324328 return ;
325329
326330 default :
@@ -333,6 +337,7 @@ function validateBenefitStructure(benefit: PromoCodeBenefit): void {
333337 *
334338 * @param pricing - validated promo pricing
335339 * @param utm - optional UTM data
340+ * @returns promo data for payment checksum
336341 */
337342export function buildPaymentPromoData ( pricing : PromoCodePricingResult , utm ?: Utm ) : PaymentPromoData {
338343 return {
@@ -388,26 +393,6 @@ export default class PromoCodeService {
388393 return promoCode ;
389394 }
390395
391- /**
392- * Validates loaded promo code against limits and expiry.
393- *
394- * @param promoCode - promo code model
395- * @param userId - user id
396- * @param workspaceId - workspace id
397- */
398- private async validateLoadedPromoCode (
399- promoCode : PromoCodeModel ,
400- userId : string ,
401- workspaceId : string
402- ) : Promise < void > {
403- if ( promoCode . expiresAt && new Date ( ) > new Date ( promoCode . expiresAt ) ) {
404- throw new PromoCodeError ( PromoCodeErrorCode . Invalid , 'Promo code expired' ) ;
405- }
406-
407- validateBenefitStructure ( promoCode . benefit ) ;
408- await this . validateUsageLimits ( promoCode , userId , new ObjectId ( workspaceId ) ) ;
409- }
410-
411396 /**
412397 * Validates promo code by id for one selected plan and returns final price.
413398 *
@@ -437,32 +422,6 @@ export default class PromoCodeService {
437422 return this . buildPricingResult ( promoCode , plan ) ;
438423 }
439424
440- /**
441- * Builds pricing result for validated promo code and plan.
442- *
443- * @param promoCode - promo code model
444- * @param plan - selected plan
445- */
446- private buildPricingResult ( promoCode : PromoCodeModel , plan : PlanModel ) : PromoCodePricingResult {
447- if ( promoCode . benefit . type === 'grant_plan' ) {
448- throw new PromoCodeError ( PromoCodeErrorCode . Invalid , 'Grant plan promo cannot be used in payment' ) ;
449- }
450-
451- const price = calculatePromoCodePlanPrice ( promoCode . benefit , plan ) ;
452-
453- if ( ! price . isApplicable ) {
454- throw new PromoCodeError ( PromoCodeErrorCode . Invalid , 'Promo code is not applicable to selected plan' ) ;
455- }
456-
457- return {
458- promoCode,
459- benefitType : promoCode . benefit . type ,
460- originalAmount : price . originalAmount ,
461- finalAmount : price . finalAmount ,
462- discountAmount : price . discountAmount ,
463- } ;
464- }
465-
466425 /**
467426 * Builds preview prices for visible plans.
468427 *
@@ -599,6 +558,53 @@ export default class PromoCodeService {
599558 }
600559 }
601560
561+ /**
562+ * Validates loaded promo code against limits and expiry.
563+ *
564+ * @param promoCode - promo code model
565+ * @param userId - user id
566+ * @param workspaceId - workspace id
567+ */
568+ private async validateLoadedPromoCode (
569+ promoCode : PromoCodeModel ,
570+ userId : string ,
571+ workspaceId : string
572+ ) : Promise < void > {
573+ if ( promoCode . expiresAt && new Date ( ) > new Date ( promoCode . expiresAt ) ) {
574+ throw new PromoCodeError ( PromoCodeErrorCode . Invalid , 'Promo code expired' ) ;
575+ }
576+
577+ validateBenefitStructure ( promoCode . benefit ) ;
578+ await this . validateUsageLimits ( promoCode , userId , new ObjectId ( workspaceId ) ) ;
579+ }
580+
581+ /**
582+ * Builds pricing result for validated promo code and plan.
583+ *
584+ * @param promoCode - promo code model
585+ * @param plan - selected plan
586+ * @returns validated promo pricing for selected plan
587+ */
588+ private buildPricingResult ( promoCode : PromoCodeModel , plan : PlanModel ) : PromoCodePricingResult {
589+ if ( promoCode . benefit . type === 'grant_plan' ) {
590+ throw new PromoCodeError ( PromoCodeErrorCode . Invalid , 'Grant plan promo cannot be used in payment' ) ;
591+ }
592+
593+ const price = calculatePromoCodePlanPrice ( promoCode . benefit , plan ) ;
594+
595+ if ( ! price . isApplicable ) {
596+ throw new PromoCodeError ( PromoCodeErrorCode . Invalid , 'Promo code is not applicable to selected plan' ) ;
597+ }
598+
599+ return {
600+ promoCode,
601+ benefitType : promoCode . benefit . type ,
602+ originalAmount : price . originalAmount ,
603+ finalAmount : price . finalAmount ,
604+ discountAmount : price . discountAmount ,
605+ } ;
606+ }
607+
602608 /**
603609 * Validates all usage limits.
604610 *
0 commit comments