chore(shorebird_code_push_protocol): use Money object instead of int for dollar values (#820)

This commit is contained in:
Bryan Oltman
2023-07-11 12:30:03 -04:00
committed by GitHub
parent 030510d4ff
commit 0397ecc705
21 changed files with 66 additions and 35 deletions
@@ -42,8 +42,6 @@ class AccountUsageCommand extends ShorebirdCommand
extension on GetUsageResponse {
String prettyPrint() {
final currencyFormatter = NumberFormat('#,##0.00', 'en_US');
const cellStyle = CellStyle(
paddingLeft: 1,
paddingRight: 1,
@@ -99,7 +97,7 @@ ${Table(
${styleBold.wrap('${lightCyan.wrap(remainingPatchInstalls)} patch installs remaining in the current billing period.')}
Current Billing Period: ${lightCyan.wrap(DateFormat.yMMMd().format(currentPeriodStart))} - ${lightCyan.wrap(DateFormat.yMMMd().format(currentPeriodEnd))}
Month-to-date cost: ${lightCyan.wrap('\$${currencyFormatter.format(currentPeriodCost / 100.0)}')}
Month-to-date cost: ${lightCyan.wrap(currentPeriodCost.toString())}
${styleBold.wrap('*Usage data is not reported in real-time and may be delayed by up to 48 hours.')}''';
}
@@ -30,7 +30,6 @@ Defaults to the app_id in "shorebird.yaml".''',
help: 'Release without confirmation if there are no errors.',
negatable: false,
);
;
}
@override
@@ -1,5 +1,5 @@
import 'package:shorebird_cli/src/shorebird_environment.dart';
import 'package:shorebird_cli/src/process.dart';
import 'package:shorebird_cli/src/shorebird_environment.dart';
import 'package:shorebird_cli/src/validators/validators.dart';
import 'package:version/version.dart';
+1
View File
@@ -23,6 +23,7 @@ dependencies:
json_annotation: ^4.8.0
mason_logger: ^0.2.4
meta: ^1.9.0
money2: ^3.4.1
path: ^1.8.3
platform: ^3.1.0
propertylistserialization: ^1.3.0
@@ -1,6 +1,7 @@
import 'package:http/http.dart' as http;
import 'package:mason_logger/mason_logger.dart';
import 'package:mocktail/mocktail.dart';
import 'package:money2/money2.dart';
import 'package:path/path.dart' as p;
import 'package:platform/platform.dart';
import 'package:scoped/scoped.dart';
@@ -1679,9 +1680,9 @@ Please bump your version number and try again.''',
test('returns usage when succeeds', () async {
final usage = GetUsageResponse(
plan: const ShorebirdPlan(
plan: ShorebirdPlan(
name: 'Hobby',
monthlyCost: 0,
monthlyCost: Money.fromIntWithCurrency(0, usd),
patchInstallLimit: 1000,
maxTeamSize: 1,
),
@@ -1693,7 +1694,7 @@ Please bump your version number and try again.''',
),
],
patchInstallLimit: 20000,
currentPeriodCost: 0,
currentPeriodCost: Money.fromIntWithCurrency(0, usd),
currentPeriodStart: DateTime(2023),
currentPeriodEnd: DateTime(2023, 2),
);
@@ -6,8 +6,8 @@ import 'package:scoped/scoped.dart';
import 'package:shorebird_cli/src/auth/auth.dart' hide auth;
import 'package:shorebird_cli/src/command_runner.dart';
import 'package:shorebird_cli/src/logger.dart' hide logger;
import 'package:shorebird_cli/src/shorebird_environment.dart';
import 'package:shorebird_cli/src/process.dart';
import 'package:shorebird_cli/src/shorebird_environment.dart';
import 'package:shorebird_cli/src/version.dart';
import 'package:test/test.dart';
@@ -1,6 +1,7 @@
import 'package:intl/intl.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:mocktail/mocktail.dart';
import 'package:money2/money2.dart';
import 'package:scoped/scoped.dart';
import 'package:shorebird_cli/src/auth/auth.dart';
import 'package:shorebird_cli/src/code_push_client_wrapper.dart';
@@ -68,9 +69,9 @@ void main() {
test('exits with code 0 when usage is fetched.', () async {
final usage = GetUsageResponse(
plan: const ShorebirdPlan(
plan: ShorebirdPlan(
name: 'Team',
monthlyCost: 2000,
monthlyCost: Money.fromIntWithCurrency(2000, usd),
patchInstallLimit: 1000,
maxTeamSize: 1,
),
@@ -87,7 +88,7 @@ void main() {
),
],
patchInstallLimit: 20000,
currentPeriodCost: 2000,
currentPeriodCost: Money.fromIntWithCurrency(2000, usd),
currentPeriodStart: DateTime(2023),
currentPeriodEnd: DateTime(2023, 2),
);
@@ -129,9 +130,9 @@ ${styleBold.wrap('*Usage data is not reported in real-time and may be delayed by
test('exits with code 0 when usage is fetched (unlimited).', () async {
final usage = GetUsageResponse(
plan: const ShorebirdPlan(
plan: ShorebirdPlan(
name: 'Hobby',
monthlyCost: 0,
monthlyCost: Money.fromIntWithCurrency(0, usd),
patchInstallLimit: 1000,
maxTeamSize: 1,
),
@@ -147,7 +148,7 @@ ${styleBold.wrap('*Usage data is not reported in real-time and may be delayed by
patchInstallCount: 42,
),
],
currentPeriodCost: 0,
currentPeriodCost: Money.fromIntWithCurrency(0, usd),
currentPeriodStart: DateTime(2023),
currentPeriodEnd: DateTime(2023, 2),
);
@@ -28,7 +28,6 @@ void main() {
startProcess = _MockProcess();
shorebirdProcess = ShorebirdProcess(
processWrapper: processWrapper,
engineConfig: const EngineConfig.empty(),
);
when(
@@ -5,8 +5,8 @@ import 'package:path/path.dart' as p;
import 'package:platform/platform.dart';
import 'package:scoped/scoped.dart';
import 'package:shorebird_cli/src/platform.dart';
import 'package:shorebird_cli/src/shorebird_environment.dart';
import 'package:shorebird_cli/src/process.dart';
import 'package:shorebird_cli/src/shorebird_environment.dart';
import 'package:shorebird_cli/src/validators/validators.dart';
import 'package:test/test.dart';
@@ -10,6 +10,7 @@ environment:
dependencies:
http: ^1.0.0
money2: ^3.4.1
shorebird_code_push_protocol:
path: ../shorebird_code_push_protocol
@@ -4,6 +4,7 @@ import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:mocktail/mocktail.dart';
import 'package:money2/money2.dart';
import 'package:path/path.dart' as path;
import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
import 'package:test/test.dart';
@@ -1930,9 +1931,9 @@ void main() {
test('completes when request succeeds', () async {
final expected = GetUsageResponse(
plan: const ShorebirdPlan(
plan: ShorebirdPlan(
name: 'Hobby',
monthlyCost: 0,
monthlyCost: Money.fromIntWithCurrency(0, usd),
patchInstallLimit: 1000,
maxTeamSize: 1,
),
@@ -1944,7 +1945,7 @@ void main() {
)
],
patchInstallLimit: 1337,
currentPeriodCost: 0,
currentPeriodCost: Money.fromIntWithCurrency(0, usd),
currentPeriodStart: DateTime(2023),
currentPeriodEnd: DateTime(2023, 2),
);
@@ -1 +1,2 @@
export 'money_converter.dart';
export 'timestamp_converter.dart';
@@ -0,0 +1,19 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:money2/money2.dart';
/// The US dollar.
Currency get usd => Currency.create('USD', 2);
/// {@template money_converter}
/// Converts between [Money] and [String].
/// {@endtemplate}
class MoneyConverter implements JsonConverter<Money, String> {
/// {@macro money_converter}
const MoneyConverter();
@override
Money fromJson(String cents) => Money.parseWithCurrency(cents, usd);
@override
String toJson(Money money) => money.minorUnits.toString();
}
@@ -1,4 +1,5 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:money2/money2.dart';
import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart';
part 'get_usage_response.g.dart';
@@ -39,7 +40,8 @@ class GetUsageResponse {
/// The total cost so far for the current billing period. Includes base
/// monthly cost and any overages.
final int currentPeriodCost;
@MoneyConverter()
final Money currentPeriodCost;
/// The upper limit of patch installs for the current billing period.
/// If `null`, there is no limit.
@@ -25,8 +25,8 @@ GetUsageResponse _$GetUsageResponseFromJson(Map<String, dynamic> json) =>
'current_period_start', (v) => DateTime.parse(v as String)),
currentPeriodEnd: $checkedConvert(
'current_period_end', (v) => DateTime.parse(v as String)),
currentPeriodCost:
$checkedConvert('current_period_cost', (v) => v as int),
currentPeriodCost: $checkedConvert('current_period_cost',
(v) => const MoneyConverter().fromJson(v as String)),
patchInstallLimit:
$checkedConvert('patch_install_limit', (v) => v as int?),
);
@@ -46,7 +46,8 @@ Map<String, dynamic> _$GetUsageResponseToJson(GetUsageResponse instance) =>
'apps': instance.apps.map((e) => e.toJson()).toList(),
'current_period_start': instance.currentPeriodStart.toIso8601String(),
'current_period_end': instance.currentPeriodEnd.toIso8601String(),
'current_period_cost': instance.currentPeriodCost,
'current_period_cost':
const MoneyConverter().toJson(instance.currentPeriodCost),
'patch_install_limit': instance.patchInstallLimit,
};
@@ -1,4 +1,5 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:money2/money2.dart';
import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart';
part 'shorebird_plan.g.dart';
@@ -25,8 +26,9 @@ class ShorebirdPlan {
/// The name of the plan.
final String name;
/// Billing rate, in cents.
final int monthlyCost;
/// Monthly billing rate.
@MoneyConverter()
final Money monthlyCost;
/// The number of patch installs allowed per billing period. This will be null
/// for accounts with unlimited patch installs.
@@ -15,7 +15,8 @@ ShorebirdPlan _$ShorebirdPlanFromJson(Map<String, dynamic> json) =>
($checkedConvert) {
final val = ShorebirdPlan(
name: $checkedConvert('name', (v) => v as String),
monthlyCost: $checkedConvert('monthly_cost', (v) => v as int),
monthlyCost: $checkedConvert('monthly_cost',
(v) => const MoneyConverter().fromJson(v as String)),
patchInstallLimit:
$checkedConvert('patch_install_limit', (v) => v as int?),
maxTeamSize: $checkedConvert('max_team_size', (v) => v as int?),
@@ -32,7 +33,7 @@ ShorebirdPlan _$ShorebirdPlanFromJson(Map<String, dynamic> json) =>
Map<String, dynamic> _$ShorebirdPlanToJson(ShorebirdPlan instance) =>
<String, dynamic>{
'name': instance.name,
'monthly_cost': instance.monthlyCost,
'monthly_cost': const MoneyConverter().toJson(instance.monthlyCost),
'patch_install_limit': instance.patchInstallLimit,
'max_team_size': instance.maxTeamSize,
};
@@ -10,6 +10,7 @@ environment:
dependencies:
json_annotation: ^4.8.0
money2: ^3.4.1
dev_dependencies:
build_runner: ^2.0.0
@@ -1,3 +1,4 @@
import 'package:money2/money2.dart';
import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart';
import 'package:test/test.dart';
@@ -5,9 +6,9 @@ void main() {
group(GetUsageResponse, () {
test('can be (de)serialized', () {
final response = GetUsageResponse(
plan: const ShorebirdPlan(
plan: ShorebirdPlan(
name: 'Hobby',
monthlyCost: 0,
monthlyCost: Money.fromIntWithCurrency(0, usd),
patchInstallLimit: 1000,
maxTeamSize: 1,
),
@@ -15,7 +16,7 @@ void main() {
const AppUsage(id: 'app-id', name: 'My app', patchInstallCount: 1337),
],
patchInstallLimit: 42,
currentPeriodCost: 0,
currentPeriodCost: Money.fromIntWithCurrency(0, usd),
currentPeriodStart: DateTime(2021),
currentPeriodEnd: DateTime(2021, 1, 2),
);
@@ -1,12 +1,13 @@
import 'package:money2/money2.dart';
import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart';
import 'package:test/test.dart';
void main() {
group(ShorebirdPlan, () {
test('can be (de)serialized', () {
const plan = ShorebirdPlan(
final plan = ShorebirdPlan(
name: 'Hobby',
monthlyCost: 0,
monthlyCost: Money.fromIntWithCurrency(0, usd),
patchInstallLimit: 1000,
maxTeamSize: 1,
);
@@ -1,11 +1,12 @@
import 'package:money2/money2.dart';
import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart';
import 'package:test/test.dart';
void main() {
group(Subscription, () {
const plan = ShorebirdPlan(
final plan = ShorebirdPlan(
name: 'Hobby',
monthlyCost: 0,
monthlyCost: Money.fromIntWithCurrency(0, usd),
patchInstallLimit: 1000,
maxTeamSize: 1,
);