180 lines
6.1 KiB
Dart
180 lines
6.1 KiB
Dart
import 'package:commons_core/commons_core.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:tane/data/variety_repository.dart';
|
|
import 'package:tane/db/database.dart';
|
|
import 'package:tane/db/enums.dart';
|
|
|
|
import '../support/test_support.dart';
|
|
|
|
void main() {
|
|
late AppDatabase db;
|
|
late VarietyRepository repo;
|
|
late String varietyId;
|
|
setUp(() async {
|
|
db = newTestDatabase();
|
|
repo = newTestRepository(db);
|
|
varietyId = await repo.addQuickVariety(label: 'Tomate rosa');
|
|
});
|
|
tearDown(() => db.close());
|
|
|
|
Future<Movement> movementById(String id) =>
|
|
(db.select(db.movements)..where((m) => m.id.equals(id))).getSingle();
|
|
|
|
Future<Lot> lotById(String id) =>
|
|
(db.select(db.lots)..where((l) => l.id.equals(id))).getSingle();
|
|
|
|
test('a plain gift records just the given movement', () async {
|
|
final lotId = await repo.addLot(varietyId: varietyId);
|
|
|
|
final result = await repo.recordHandover(
|
|
lotId: lotId,
|
|
direction: HandoverDirection.iGave,
|
|
counterparty: 'María',
|
|
);
|
|
|
|
expect(result.saleId, isNull);
|
|
expect(result.plantareId, isNull);
|
|
final movement = await movementById(result.movementId);
|
|
expect(movement.type, MovementType.given);
|
|
expect(movement.lotId, lotId);
|
|
expect(movement.notes, 'María');
|
|
expect(movement.plantareId, isNull);
|
|
expect(await repo.watchSales().first, isEmpty);
|
|
expect(await repo.watchPlantares().first, isEmpty);
|
|
});
|
|
|
|
test(
|
|
'giving all depletes the lot, privatizes it and drops its price',
|
|
() async {
|
|
final lotId = await repo.addLot(
|
|
varietyId: varietyId,
|
|
quantity: const Quantity(kind: QuantityKind.grams, count: 40),
|
|
abundance: Abundance.plentyToShare,
|
|
offerStatus: OfferStatus.sell,
|
|
priceAmount: 3,
|
|
priceCurrency: '€',
|
|
);
|
|
|
|
final result = await repo.recordHandover(
|
|
lotId: lotId,
|
|
direction: HandoverDirection.iGave,
|
|
gaveAll: true,
|
|
);
|
|
|
|
// The movement carries what actually moved: the lot's whole quantity.
|
|
final movement = await movementById(result.movementId);
|
|
expect(movement.quantityKind, QuantityKind.grams.name);
|
|
expect(movement.quantityPrecise, 40);
|
|
|
|
// The lot stays as an empty jar, withdrawn from the market.
|
|
final lot = await lotById(lotId);
|
|
expect(lot.quantityPrecise, 0);
|
|
expect(lot.quantityKind, QuantityKind.grams.name);
|
|
expect(lot.abundance, isNull);
|
|
expect(lot.offerStatus, OfferStatus.private);
|
|
expect(lot.priceAmount, isNull);
|
|
expect(lot.priceCurrency, isNull);
|
|
expect(
|
|
(await repo.shareableLots()).where((l) => l.lotId == lotId),
|
|
isEmpty,
|
|
);
|
|
},
|
|
);
|
|
|
|
test('giving part keeps the lot open and offered', () async {
|
|
final lotId = await repo.addLot(
|
|
varietyId: varietyId,
|
|
quantity: const Quantity(kind: QuantityKind.grams, count: 40),
|
|
offerStatus: OfferStatus.shared,
|
|
);
|
|
|
|
final result = await repo.recordHandover(
|
|
lotId: lotId,
|
|
direction: HandoverDirection.iGave,
|
|
quantity: const Quantity(kind: QuantityKind.grams, count: 10),
|
|
);
|
|
|
|
final movement = await movementById(result.movementId);
|
|
expect(movement.quantityPrecise, 10);
|
|
final lot = await lotById(lotId);
|
|
expect(lot.quantityPrecise, 40); // untouched: the log holds the history
|
|
expect(lot.offerStatus, OfferStatus.shared);
|
|
expect(
|
|
(await repo.shareableLots()).where((l) => l.lotId == lotId),
|
|
hasLength(1),
|
|
);
|
|
});
|
|
|
|
test('a payment on a give creates the matching sale record', () async {
|
|
final lotId = await repo.addLot(varietyId: varietyId);
|
|
|
|
final result = await repo.recordHandover(
|
|
lotId: lotId,
|
|
direction: HandoverDirection.iGave,
|
|
counterparty: 'María',
|
|
withPayment: true,
|
|
paymentAmount: 2.5,
|
|
paymentCurrency: 'Ğ1',
|
|
);
|
|
|
|
final sales = await repo.watchSales().first;
|
|
expect(sales, hasLength(1));
|
|
expect(sales.single.id, result.saleId);
|
|
expect(sales.single.direction, SaleDirection.iSold);
|
|
expect(sales.single.varietyId, varietyId);
|
|
expect(sales.single.counterparty, 'María');
|
|
expect(sales.single.amount, 2.5);
|
|
expect(sales.single.currency, 'Ğ1');
|
|
});
|
|
|
|
test('a promise on a give creates a plantare owed to me, linked from the '
|
|
'movement', () async {
|
|
final lotId = await repo.addLot(varietyId: varietyId);
|
|
|
|
final result = await repo.recordHandover(
|
|
lotId: lotId,
|
|
direction: HandoverDirection.iGave,
|
|
counterparty: 'María',
|
|
withPromise: true,
|
|
promiseOwedDescription: 'un puñado la próxima temporada',
|
|
);
|
|
|
|
final plantares = await repo.watchPlantares().first;
|
|
expect(plantares, hasLength(1));
|
|
expect(plantares.single.id, result.plantareId);
|
|
expect(plantares.single.direction, PlantareDirection.owedToMe);
|
|
expect(plantares.single.varietyId, varietyId);
|
|
expect(plantares.single.counterparty, 'María');
|
|
expect(plantares.single.owedDescription, 'un puñado la próxima temporada');
|
|
// The link the model reserved: the movement carries the plantare id.
|
|
final movement = await movementById(result.movementId);
|
|
expect(movement.plantareId, result.plantareId);
|
|
});
|
|
|
|
test('receiving with payment and promise mirrors the directions', () async {
|
|
final lotId = await repo.addLot(
|
|
varietyId: varietyId,
|
|
quantity: const Quantity(kind: QuantityKind.grams, count: 40),
|
|
);
|
|
|
|
final result = await repo.recordHandover(
|
|
lotId: lotId,
|
|
direction: HandoverDirection.iReceived,
|
|
// Meaningless on a receive; must not deplete anything.
|
|
gaveAll: true,
|
|
withPayment: true,
|
|
paymentAmount: 5,
|
|
paymentCurrency: '€',
|
|
withPromise: true,
|
|
);
|
|
|
|
final movement = await movementById(result.movementId);
|
|
expect(movement.type, MovementType.received);
|
|
final lot = await lotById(lotId);
|
|
expect(lot.quantityPrecise, 40);
|
|
final sales = await repo.watchSales().first;
|
|
expect(sales.single.direction, SaleDirection.iBought);
|
|
final plantares = await repo.watchPlantares().first;
|
|
expect(plantares.single.direction, PlantareDirection.iReturn);
|
|
});
|
|
}
|