@@ -529,25 +529,199 @@ func TestFromBillingPrice(t *testing.T) {
529529 assert .Equal (t , "volume" , disc )
530530 })
531531
532- t .Run ("dynamic price returns conflict error" , func (t * testing.T ) {
533- p := productcatalog .NewPriceFrom (productcatalog.DynamicPrice {})
532+ t .Run ("dynamic price translates to unit price of amount 1" , func (t * testing.T ) {
533+ p := productcatalog .NewPriceFrom (productcatalog.DynamicPrice {
534+ Multiplier : decimal .NewFromFloat (1.2 ),
535+ })
534536
535- _ , err := ToAPIBillingPrice (p )
536- require .Error (t , err )
537- assert .True (t , models .IsGenericConflictError (err ))
538- assert .Contains (t , err .Error (), "dynamic price is not supported in v3 API" )
537+ result , err := ToAPIBillingPrice (p )
538+ require .NoError (t , err )
539+
540+ disc , err := result .Discriminator ()
541+ require .NoError (t , err )
542+ assert .Equal (t , "unit" , disc )
543+
544+ unit , err := result .AsBillingPriceUnit ()
545+ require .NoError (t , err )
546+ assert .Equal (t , api .Numeric ("1" ), unit .Amount )
547+ })
548+
549+ t .Run ("package price translates to unit price with package amount" , func (t * testing.T ) {
550+ p := productcatalog .NewPriceFrom (productcatalog.PackagePrice {
551+ Amount : decimal .NewFromFloat (0.5 ),
552+ QuantityPerPackage : decimal .NewFromInt (1000 ),
553+ })
554+
555+ result , err := ToAPIBillingPrice (p )
556+ require .NoError (t , err )
557+
558+ disc , err := result .Discriminator ()
559+ require .NoError (t , err )
560+ assert .Equal (t , "unit" , disc )
561+
562+ unit , err := result .AsBillingPriceUnit ()
563+ require .NoError (t , err )
564+ assert .Equal (t , api .Numeric ("0.5" ), unit .Amount )
565+ })
566+ }
567+
568+ func TestToAPIBillingRateCardUnitConfig (t * testing.T ) {
569+ t .Run ("nil price has no unit config" , func (t * testing.T ) {
570+ result , err := ToAPIBillingRateCardUnitConfig (nil )
571+ require .NoError (t , err )
572+ assert .Nil (t , result )
573+ })
574+
575+ t .Run ("flat price has no unit config" , func (t * testing.T ) {
576+ p := productcatalog .NewPriceFrom (productcatalog.FlatPrice {Amount : decimal .NewFromFloat (5 )})
577+
578+ result , err := ToAPIBillingRateCardUnitConfig (p )
579+ require .NoError (t , err )
580+ assert .Nil (t , result )
581+ })
582+
583+ t .Run ("unit price has no unit config" , func (t * testing.T ) {
584+ p := productcatalog .NewPriceFrom (productcatalog.UnitPrice {Amount : decimal .NewFromFloat (0.05 )})
585+
586+ result , err := ToAPIBillingRateCardUnitConfig (p )
587+ require .NoError (t , err )
588+ assert .Nil (t , result )
539589 })
540590
541- t .Run ("package price returns conflict error" , func (t * testing.T ) {
591+ t .Run ("dynamic price produces multiply unit config" , func (t * testing.T ) {
592+ p := productcatalog .NewPriceFrom (productcatalog.DynamicPrice {
593+ Multiplier : decimal .NewFromFloat (1.2 ),
594+ })
595+
596+ result , err := ToAPIBillingRateCardUnitConfig (p )
597+ require .NoError (t , err )
598+ require .NotNil (t , result )
599+ assert .Equal (t , api .BillingUnitConfigOperationMultiply , result .Operation )
600+ assert .Equal (t , api .Numeric ("1.2" ), result .ConversionFactor )
601+ assert .Nil (t , result .Rounding )
602+ assert .Nil (t , result .Precision )
603+ assert .Nil (t , result .DisplayUnit )
604+ })
605+
606+ t .Run ("package price produces divide unit config with ceiling rounding" , func (t * testing.T ) {
542607 p := productcatalog .NewPriceFrom (productcatalog.PackagePrice {
543608 Amount : decimal .NewFromFloat (10 ),
544- QuantityPerPackage : decimal .NewFromInt (100 ),
609+ QuantityPerPackage : decimal .NewFromInt (1000 ),
545610 })
546611
547- _ , err := ToAPIBillingPrice (p )
548- require .Error (t , err )
549- assert .True (t , models .IsGenericConflictError (err ))
550- assert .Contains (t , err .Error (), "package price is not supported in v3 API" )
612+ result , err := ToAPIBillingRateCardUnitConfig (p )
613+ require .NoError (t , err )
614+ require .NotNil (t , result )
615+ assert .Equal (t , api .BillingUnitConfigOperationDivide , result .Operation )
616+ assert .Equal (t , api .Numeric ("1000" ), result .ConversionFactor )
617+ require .NotNil (t , result .Rounding )
618+ assert .Equal (t , api .BillingUnitConfigRoundingModeCeiling , * result .Rounding )
619+ })
620+ }
621+
622+ func TestFromRateCard_DynamicAndPackagePrices (t * testing.T ) {
623+ cadence , err := datetime .ISODurationString ("P1M" ).Parse ()
624+ require .NoError (t , err )
625+
626+ t .Run ("dynamic price renders as unit price plus multiply unit config and preserves commitments" , func (t * testing.T ) {
627+ minAmt := decimal .NewFromFloat (10 )
628+ maxAmt := decimal .NewFromFloat (100 )
629+ price := productcatalog .NewPriceFrom (productcatalog.DynamicPrice {
630+ Multiplier : decimal .NewFromFloat (1.2 ),
631+ Commitments : productcatalog.Commitments {
632+ MinimumAmount : & minAmt ,
633+ MaximumAmount : & maxAmt ,
634+ },
635+ })
636+
637+ rc := & productcatalog.UsageBasedRateCard {
638+ RateCardMeta : productcatalog.RateCardMeta {
639+ Key : "tokens" ,
640+ Name : "Tokens" ,
641+ Price : price ,
642+ },
643+ BillingCadence : cadence ,
644+ }
645+
646+ result , err := ToAPIBillingRateCard (rc )
647+ require .NoError (t , err )
648+
649+ disc , err := result .Price .Discriminator ()
650+ require .NoError (t , err )
651+ assert .Equal (t , "unit" , disc )
652+
653+ unit , err := result .Price .AsBillingPriceUnit ()
654+ require .NoError (t , err )
655+ assert .Equal (t , api .Numeric ("1" ), unit .Amount )
656+
657+ require .NotNil (t , result .UnitConfig )
658+ assert .Equal (t , api .BillingUnitConfigOperationMultiply , result .UnitConfig .Operation )
659+ assert .Equal (t , api .Numeric ("1.2" ), result .UnitConfig .ConversionFactor )
660+ assert .Nil (t , result .UnitConfig .Rounding )
661+
662+ require .NotNil (t , result .Commitments )
663+ assert .Equal (t , lo .ToPtr (api .Numeric ("10" )), result .Commitments .MinimumAmount )
664+ assert .Equal (t , lo .ToPtr (api .Numeric ("100" )), result .Commitments .MaximumAmount )
665+ })
666+
667+ t .Run ("package price renders as unit price plus divide unit config and preserves commitments" , func (t * testing.T ) {
668+ minAmt := decimal .NewFromFloat (5 )
669+ price := productcatalog .NewPriceFrom (productcatalog.PackagePrice {
670+ Amount : decimal .NewFromFloat (0.5 ),
671+ QuantityPerPackage : decimal .NewFromInt (1000 ),
672+ Commitments : productcatalog.Commitments {
673+ MinimumAmount : & minAmt ,
674+ },
675+ })
676+
677+ rc := & productcatalog.UsageBasedRateCard {
678+ RateCardMeta : productcatalog.RateCardMeta {
679+ Key : "api-calls" ,
680+ Name : "API Calls" ,
681+ Price : price ,
682+ },
683+ BillingCadence : cadence ,
684+ }
685+
686+ result , err := ToAPIBillingRateCard (rc )
687+ require .NoError (t , err )
688+
689+ disc , err := result .Price .Discriminator ()
690+ require .NoError (t , err )
691+ assert .Equal (t , "unit" , disc )
692+
693+ unit , err := result .Price .AsBillingPriceUnit ()
694+ require .NoError (t , err )
695+ assert .Equal (t , api .Numeric ("0.5" ), unit .Amount )
696+
697+ require .NotNil (t , result .UnitConfig )
698+ assert .Equal (t , api .BillingUnitConfigOperationDivide , result .UnitConfig .Operation )
699+ assert .Equal (t , api .Numeric ("1000" ), result .UnitConfig .ConversionFactor )
700+ require .NotNil (t , result .UnitConfig .Rounding )
701+ assert .Equal (t , api .BillingUnitConfigRoundingModeCeiling , * result .UnitConfig .Rounding )
702+
703+ require .NotNil (t , result .Commitments )
704+ assert .Equal (t , lo .ToPtr (api .Numeric ("5" )), result .Commitments .MinimumAmount )
705+ assert .Nil (t , result .Commitments .MaximumAmount )
706+ })
707+
708+ t .Run ("unit price has no unit config on rate card" , func (t * testing.T ) {
709+ price := productcatalog .NewPriceFrom (productcatalog.UnitPrice {
710+ Amount : decimal .NewFromFloat (0.05 ),
711+ })
712+
713+ rc := & productcatalog.UsageBasedRateCard {
714+ RateCardMeta : productcatalog.RateCardMeta {
715+ Key : "api-calls" ,
716+ Name : "API Calls" ,
717+ Price : price ,
718+ },
719+ BillingCadence : cadence ,
720+ }
721+
722+ result , err := ToAPIBillingRateCard (rc )
723+ require .NoError (t , err )
724+ assert .Nil (t , result .UnitConfig )
551725 })
552726}
553727
0 commit comments