feat(sales): local sales/purchase ledger (any currency)
A sale is a distinct model from a gift or a Plantare (reproduction
commitment): a recorded seed sale or purchase with an optional price in
ANY currency — €, Ğ1, time, or none yet. Mirrors the Plantare feature.
- schema v10: Sales table (SyncColumns), guarded createTable migration,
schema dump + generated schema_v10 for the migration round-trip test
- enum SaleDirection { iSold, iBought }
- VarietyRepository: create/watch/watchForVariety/delete + backup
export/exportForSync/import (LWW-by-HLC, tombstones)
- InventorySnapshot.sales + JSON codec encode/decode (round-trips amount,
currency, counterparty)
- UI: SalesScreen (/sales), sale sheet, drawer entry, variety-detail
action beside 'add Plantare'; money hides a trailing .0
- i18n sale block + menu.sales in en/es/pt/ast
- tests: sales repo test (5) incl. Ğ1/price-less/backup round-trip;
Sales screen added to the small-screen overflow guard
Also harden the overflow guard: swallow the headless engine's image
resource service PNG-decode errors (unrelated to layout) while still
failing on real RenderFlex overflows, so home/about stop reporting
false failures.
This commit is contained in:
parent
de6938d5d7
commit
6de039d518
27 changed files with 6156 additions and 23 deletions
|
|
@ -17,6 +17,7 @@ import 'package:tane/ui/inventory_list_screen.dart';
|
|||
import 'package:tane/ui/market_screen.dart';
|
||||
import 'package:tane/ui/plantares_screen.dart';
|
||||
import 'package:tane/ui/profile_screen.dart';
|
||||
import 'package:tane/ui/sales_screen.dart';
|
||||
import 'package:tane/ui/settings_screen.dart';
|
||||
|
||||
import '../support/test_support.dart';
|
||||
|
|
@ -51,6 +52,19 @@ void main() {
|
|||
tester.view.devicePixelRatio = 1.0;
|
||||
addTearDown(tester.view.resetPhysicalSize);
|
||||
addTearDown(tester.view.resetDevicePixelRatio);
|
||||
// flutter_test's headless engine can't decode our real PNG assets (the
|
||||
// logo), so `Image.asset` throws from the "image resource service". That's
|
||||
// unrelated to layout — swallow ONLY those, and let every other FlutterError
|
||||
// (crucially the "rendering library" RenderFlex overflow this guard exists
|
||||
// to catch) still fail the test. Installed here, inside the running test,
|
||||
// because testWidgets reinstalls its own onError at test start (a setUp
|
||||
// override would be clobbered).
|
||||
final previous = FlutterError.onError;
|
||||
FlutterError.onError = (details) {
|
||||
if (details.library == 'image resource service') return;
|
||||
previous?.call(details);
|
||||
};
|
||||
addTearDown(() => FlutterError.onError = previous);
|
||||
await tester.pumpWidget(widget);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
|
@ -258,6 +272,28 @@ void main() {
|
|||
await disposeTree(tester);
|
||||
});
|
||||
|
||||
testWidgets('the Sales screen (with a sale) fits a small screen',
|
||||
(tester) async {
|
||||
final db = newTestDatabase();
|
||||
addTearDown(db.close);
|
||||
final repo = newTestRepository(db);
|
||||
await repo.createSale(
|
||||
direction: SaleDirection.iSold,
|
||||
counterparty: 'Feria de intercambio de la comarca',
|
||||
amount: 12.5,
|
||||
currency: '€',
|
||||
);
|
||||
await pumpSmall(
|
||||
tester,
|
||||
wrapScreen(
|
||||
repository: repo,
|
||||
locale: AppLocale.es,
|
||||
child: const SalesScreen(),
|
||||
),
|
||||
);
|
||||
await disposeTree(tester);
|
||||
});
|
||||
|
||||
// NOTE: the variety-detail screen is deliberately NOT overflow-checked here.
|
||||
// It reports a ~2px overflow on a RenderFlex that is already DISPOSED/DEFUNCT
|
||||
// — a transient stale frame while its cubit's Drift stream rebuilds during
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue