diff --git a/apps/app_seeds/drift_schemas/drift_schema_v10.json b/apps/app_seeds/drift_schemas/drift_schema_v10.json new file mode 100644 index 0000000..ec9627c --- /dev/null +++ b/apps/app_seeds/drift_schemas/drift_schema_v10.json @@ -0,0 +1,2151 @@ +{ + "_meta": { + "description": "This file contains a serialized version of schema entities for drift.", + "version": "1.3.0" + }, + "options": { + "store_date_time_values_as_text": false + }, + "entities": [ + { + "id": 0, + "references": [], + "type": "table", + "data": { + "name": "varieties", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "label", + "getter_name": "label", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "species_id", + "getter_name": "speciesId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "cultivar_name", + "getter_name": "cultivarName", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "category", + "getter_name": "category", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "notes", + "getter_name": "notes", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_draft", + "getter_name": "isDraft", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_draft\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_draft\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_organic", + "getter_name": "isOrganic", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_organic\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_organic\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "needs_reproduction", + "getter_name": "needsReproduction", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"needs_reproduction\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"needs_reproduction\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "sow_months", + "getter_name": "sowMonths", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "transplant_months", + "getter_name": "transplantMonths", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "flowering_months", + "getter_name": "floweringMonths", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "fruiting_months", + "getter_name": "fruitingMonths", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "seed_harvest_months", + "getter_name": "seedHarvestMonths", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 1, + "references": [], + "type": "table", + "data": { + "name": "variety_vernacular_names", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "variety_id", + "getter_name": "varietyId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "name", + "getter_name": "name", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "language", + "getter_name": "language", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "region", + "getter_name": "region", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 2, + "references": [], + "type": "table", + "data": { + "name": "species", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "scientific_name", + "getter_name": "scientificName", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "wikidata_qid", + "getter_name": "wikidataQid", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "gbif_key", + "getter_name": "gbifKey", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "family", + "getter_name": "family", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_bundled", + "getter_name": "isBundled", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_bundled\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_bundled\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "viability_years", + "getter_name": "viabilityYears", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 3, + "references": [], + "type": "table", + "data": { + "name": "species_common_names", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "species_id", + "getter_name": "speciesId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "name", + "getter_name": "name", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "language", + "getter_name": "language", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 4, + "references": [], + "type": "table", + "data": { + "name": "lots", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "variety_id", + "getter_name": "varietyId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('\\'seed\\'')", + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(LotType.values)", + "dart_type_name": "LotType" + } + }, + { + "name": "harvest_year", + "getter_name": "harvestYear", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "harvest_month", + "getter_name": "harvestMonth", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quantity_kind", + "getter_name": "quantityKind", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quantity_precise", + "getter_name": "quantityPrecise", + "moor_type": "double", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quantity_label", + "getter_name": "quantityLabel", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "presentation", + "getter_name": "presentation", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(Presentation.values)", + "dart_type_name": "Presentation" + } + }, + { + "name": "storage_location", + "getter_name": "storageLocation", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "offer_status", + "getter_name": "offerStatus", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('\\'private\\'')", + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(OfferStatus.values)", + "dart_type_name": "OfferStatus" + } + }, + { + "name": "seedbank_id", + "getter_name": "seedbankId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "origin_name", + "getter_name": "originName", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "origin_place", + "getter_name": "originPlace", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "abundance", + "getter_name": "abundance", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(Abundance.values)", + "dart_type_name": "Abundance" + } + }, + { + "name": "preservation_format", + "getter_name": "preservationFormat", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(PreservationFormat.values)", + "dart_type_name": "PreservationFormat" + } + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 5, + "references": [], + "type": "table", + "data": { + "name": "germination_tests", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "lot_id", + "getter_name": "lotId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "tested_on", + "getter_name": "testedOn", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "sample_size", + "getter_name": "sampleSize", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "germinated_count", + "getter_name": "germinatedCount", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "notes", + "getter_name": "notes", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 6, + "references": [], + "type": "table", + "data": { + "name": "condition_checks", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "lot_id", + "getter_name": "lotId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "checked_on", + "getter_name": "checkedOn", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "container_count", + "getter_name": "containerCount", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "desiccant_state", + "getter_name": "desiccantState", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(DesiccantState.values)", + "dart_type_name": "DesiccantState" + } + }, + { + "name": "notes", + "getter_name": "notes", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 7, + "references": [], + "type": "table", + "data": { + "name": "movements", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "lot_id", + "getter_name": "lotId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "type", + "getter_name": "type", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(MovementType.values)", + "dart_type_name": "MovementType" + } + }, + { + "name": "occurred_on", + "getter_name": "occurredOn", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "counterparty_id", + "getter_name": "counterpartyId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quantity_kind", + "getter_name": "quantityKind", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quantity_precise", + "getter_name": "quantityPrecise", + "moor_type": "double", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quantity_label", + "getter_name": "quantityLabel", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "parent_movement_id", + "getter_name": "parentMovementId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "plantare_id", + "getter_name": "plantareId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "notes", + "getter_name": "notes", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 8, + "references": [], + "type": "table", + "data": { + "name": "parties", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "display_name", + "getter_name": "displayName", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "public_key", + "getter_name": "publicKey", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "kind", + "getter_name": "kind", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('\\'person\\'')", + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(PartyKind.values)", + "dart_type_name": "PartyKind" + } + }, + { + "name": "note", + "getter_name": "note", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 9, + "references": [], + "type": "table", + "data": { + "name": "attachments", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "parent_type", + "getter_name": "parentType", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(ParentType.values)", + "dart_type_name": "ParentType" + } + }, + { + "name": "parent_id", + "getter_name": "parentId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "kind", + "getter_name": "kind", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(AttachmentKind.values)", + "dart_type_name": "AttachmentKind" + } + }, + { + "name": "uri", + "getter_name": "uri", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "bytes", + "getter_name": "bytes", + "moor_type": "blob", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "mime_type", + "getter_name": "mimeType", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "sort_order", + "getter_name": "sortOrder", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 10, + "references": [], + "type": "table", + "data": { + "name": "external_links", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "parent_type", + "getter_name": "parentType", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(ParentType.values)", + "dart_type_name": "ParentType" + } + }, + { + "name": "parent_id", + "getter_name": "parentId", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "url", + "getter_name": "url", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "title", + "getter_name": "title", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 11, + "references": [], + "type": "table", + "data": { + "name": "plantares", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "variety_id", + "getter_name": "varietyId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "direction", + "getter_name": "direction", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(PlantareDirection.values)", + "dart_type_name": "PlantareDirection" + } + }, + { + "name": "counterparty", + "getter_name": "counterparty", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "owed_description", + "getter_name": "owedDescription", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "made_on", + "getter_name": "madeOn", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "due_by", + "getter_name": "dueBy", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "status", + "getter_name": "status", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('\\'open\\'')", + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(PlantareStatus.values)", + "dart_type_name": "PlantareStatus" + } + }, + { + "name": "settled_on", + "getter_name": "settledOn", + "moor_type": "int", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "note", + "getter_name": "note", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 12, + "references": [], + "type": "table", + "data": { + "name": "sales", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "getter_name": "id", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "getter_name": "createdAt", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "getter_name": "updatedAt", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_author", + "getter_name": "lastAuthor", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_deleted", + "getter_name": "isDeleted", + "moor_type": "bool", + "nullable": false, + "customConstraints": null, + "defaultConstraints": "CHECK (\"is_deleted\" IN (0, 1))", + "dialectAwareDefaultConstraints": { + "sqlite": "CHECK (\"is_deleted\" IN (0, 1))" + }, + "default_dart": "const CustomExpression('0')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "schema_row_version", + "getter_name": "schemaRowVersion", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": "const CustomExpression('1')", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "variety_id", + "getter_name": "varietyId", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "direction", + "getter_name": "direction", + "moor_type": "string", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "const EnumNameConverter(SaleDirection.values)", + "dart_type_name": "SaleDirection" + } + }, + { + "name": "counterparty", + "getter_name": "counterparty", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "amount", + "getter_name": "amount", + "moor_type": "double", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "currency", + "getter_name": "currency", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "sold_on", + "getter_name": "soldOn", + "moor_type": "int", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "note", + "getter_name": "note", + "moor_type": "string", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "without_rowid": false, + "constraints": [], + "explicit_pk": [ + "id" + ] + } + } + ], + "fixed_sql": [ + { + "name": "varieties", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"varieties\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"label\" TEXT NOT NULL, \"species_id\" TEXT NULL, \"cultivar_name\" TEXT NULL, \"category\" TEXT NULL, \"notes\" TEXT NULL, \"is_draft\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_draft\" IN (0, 1)), \"is_organic\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_organic\" IN (0, 1)), \"needs_reproduction\" INTEGER NOT NULL DEFAULT 0 CHECK (\"needs_reproduction\" IN (0, 1)), \"sow_months\" INTEGER NULL, \"transplant_months\" INTEGER NULL, \"flowering_months\" INTEGER NULL, \"fruiting_months\" INTEGER NULL, \"seed_harvest_months\" INTEGER NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "variety_vernacular_names", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"variety_vernacular_names\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"variety_id\" TEXT NOT NULL, \"name\" TEXT NOT NULL, \"language\" TEXT NULL, \"region\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "species", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"species\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"scientific_name\" TEXT NOT NULL, \"wikidata_qid\" TEXT NULL, \"gbif_key\" INTEGER NULL, \"family\" TEXT NULL, \"is_bundled\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_bundled\" IN (0, 1)), \"viability_years\" INTEGER NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "species_common_names", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"species_common_names\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"species_id\" TEXT NOT NULL, \"name\" TEXT NOT NULL, \"language\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "lots", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"lots\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"variety_id\" TEXT NOT NULL, \"type\" TEXT NOT NULL DEFAULT 'seed', \"harvest_year\" INTEGER NULL, \"harvest_month\" INTEGER NULL, \"quantity_kind\" TEXT NULL, \"quantity_precise\" REAL NULL, \"quantity_label\" TEXT NULL, \"presentation\" TEXT NULL, \"storage_location\" TEXT NULL, \"offer_status\" TEXT NOT NULL DEFAULT 'private', \"seedbank_id\" TEXT NULL, \"origin_name\" TEXT NULL, \"origin_place\" TEXT NULL, \"abundance\" TEXT NULL, \"preservation_format\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "germination_tests", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"germination_tests\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"lot_id\" TEXT NOT NULL, \"tested_on\" INTEGER NULL, \"sample_size\" INTEGER NULL, \"germinated_count\" INTEGER NULL, \"notes\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "condition_checks", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"condition_checks\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"lot_id\" TEXT NOT NULL, \"checked_on\" INTEGER NULL, \"container_count\" INTEGER NULL, \"desiccant_state\" TEXT NULL, \"notes\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "movements", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"movements\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"last_author\" TEXT NOT NULL, \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"lot_id\" TEXT NOT NULL, \"type\" TEXT NOT NULL, \"occurred_on\" INTEGER NULL, \"counterparty_id\" TEXT NULL, \"quantity_kind\" TEXT NULL, \"quantity_precise\" REAL NULL, \"quantity_label\" TEXT NULL, \"parent_movement_id\" TEXT NULL, \"plantare_id\" TEXT NULL, \"notes\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "parties", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"parties\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"display_name\" TEXT NOT NULL, \"public_key\" TEXT NULL, \"kind\" TEXT NOT NULL DEFAULT 'person', \"note\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "attachments", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"attachments\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"parent_type\" TEXT NOT NULL, \"parent_id\" TEXT NOT NULL, \"kind\" TEXT NOT NULL, \"uri\" TEXT NULL, \"bytes\" BLOB NULL, \"mime_type\" TEXT NULL, \"sort_order\" INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "external_links", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"external_links\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"parent_type\" TEXT NOT NULL, \"parent_id\" TEXT NOT NULL, \"url\" TEXT NOT NULL, \"title\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "plantares", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"plantares\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"variety_id\" TEXT NULL, \"direction\" TEXT NOT NULL, \"counterparty\" TEXT NULL, \"owed_description\" TEXT NULL, \"made_on\" INTEGER NOT NULL, \"due_by\" INTEGER NULL, \"status\" TEXT NOT NULL DEFAULT 'open', \"settled_on\" INTEGER NULL, \"note\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + }, + { + "name": "sales", + "sql": [ + { + "dialect": "sqlite", + "sql": "CREATE TABLE IF NOT EXISTS \"sales\" (\"id\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, \"updated_at\" TEXT NOT NULL, \"last_author\" TEXT NOT NULL, \"is_deleted\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_deleted\" IN (0, 1)), \"schema_row_version\" INTEGER NOT NULL DEFAULT 1, \"variety_id\" TEXT NULL, \"direction\" TEXT NOT NULL, \"counterparty\" TEXT NULL, \"amount\" REAL NULL, \"currency\" TEXT NULL, \"sold_on\" INTEGER NOT NULL, \"note\" TEXT NULL, PRIMARY KEY (\"id\"));" + } + ] + } + ] +} \ No newline at end of file diff --git a/apps/app_seeds/lib/app.dart b/apps/app_seeds/lib/app.dart index ae9fbb3..28a0a37 100644 --- a/apps/app_seeds/lib/app.dart +++ b/apps/app_seeds/lib/app.dart @@ -33,6 +33,7 @@ import 'ui/home_screen.dart'; import 'ui/intro_screen.dart'; import 'ui/inventory_list_screen.dart'; import 'ui/plantares_screen.dart'; +import 'ui/sales_screen.dart'; import 'ui/market_offer_detail_screen.dart'; import 'ui/market_screen.dart'; import 'ui/offline_banner.dart'; @@ -260,6 +261,11 @@ class TaneApp extends StatelessWidget { path: '/plantares', builder: (context, state) => const PlantaresScreen(), ), + // Local sales ledger — also inventory-adjacent, no network. + GoRoute( + path: '/sales', + builder: (context, state) => const SalesScreen(), + ), GoRoute( path: '/variety/:id', builder: (context, state) => BlocProvider( diff --git a/apps/app_seeds/lib/data/export_import/inventory_json_codec.dart b/apps/app_seeds/lib/data/export_import/inventory_json_codec.dart index 83f2f12..d10c845 100644 --- a/apps/app_seeds/lib/data/export_import/inventory_json_codec.dart +++ b/apps/app_seeds/lib/data/export_import/inventory_json_codec.dart @@ -230,6 +230,26 @@ class InventoryJsonCodec { 'note': p.note, }, ], + 'sales': [ + for (final s in snapshot.sales) + { + ..._syncMeta( + id: s.id, + createdAt: s.createdAt, + updatedAt: s.updatedAt, + lastAuthor: s.lastAuthor, + schemaRowVersion: s.schemaRowVersion, + isDeleted: s.isDeleted, + ), + 'varietyId': s.varietyId, + 'direction': s.direction.name, + 'counterparty': s.counterparty, + 'amount': s.amount, + 'currency': s.currency, + 'soldOn': s.soldOn, + 'note': s.note, + }, + ], }); } @@ -462,6 +482,24 @@ class InventoryJsonCodec { note: m['note'] as String?, ); }), + sales: _rows(root, 'sales', (m) { + return Sale( + id: _string(m, 'id'), + createdAt: _int(m, 'createdAt'), + updatedAt: _string(m, 'updatedAt'), + lastAuthor: _string(m, 'lastAuthor'), + isDeleted: _bool(m, 'isDeleted'), + schemaRowVersion: _int(m, 'schemaRowVersion', fallback: 1), + varietyId: m['varietyId'] as String?, + direction: + _enumOr(SaleDirection.values, m['direction'], SaleDirection.iSold), + counterparty: m['counterparty'] as String?, + amount: (m['amount'] as num?)?.toDouble(), + currency: m['currency'] as String?, + soldOn: _int(m, 'soldOn'), + note: m['note'] as String?, + ); + }), ); } diff --git a/apps/app_seeds/lib/data/export_import/inventory_snapshot.dart b/apps/app_seeds/lib/data/export_import/inventory_snapshot.dart index 5707250..68df583 100644 --- a/apps/app_seeds/lib/data/export_import/inventory_snapshot.dart +++ b/apps/app_seeds/lib/data/export_import/inventory_snapshot.dart @@ -31,6 +31,7 @@ class InventorySnapshot { this.parties = const [], this.attachments = const [], this.plantares = const [], + this.sales = const [], this.speciesNamesById = const {}, }); @@ -44,6 +45,7 @@ class InventorySnapshot { final List parties; final List attachments; final List plantares; + final List sales; /// speciesId → scientificName, for the species referenced by [varieties]. final Map speciesNamesById; diff --git a/apps/app_seeds/lib/data/variety_repository.dart b/apps/app_seeds/lib/data/variety_repository.dart index 8cd29cc..8989d1f 100644 --- a/apps/app_seeds/lib/data/variety_repository.dart +++ b/apps/app_seeds/lib/data/variety_repository.dart @@ -1781,6 +1781,64 @@ class VarietyRepository { ); } + // --- Sales: recorded seed sales (separate from gift/Plantare) -------------- + + /// Records a seed sale (or purchase) — price in ANY currency. Returns its id. + Future createSale({ + required SaleDirection direction, + String? varietyId, + String? counterparty, + double? amount, + String? currency, + String? note, + }) async { + final (created, updated) = await _stamp(); + final id = idGen.newId(); + await _db.into(_db.sales).insert( + SalesCompanion.insert( + id: id, + createdAt: created, + updatedAt: updated, + lastAuthor: nodeId, + direction: direction, + varietyId: Value(varietyId), + counterparty: Value(counterparty), + amount: Value(amount), + currency: Value(currency), + soldOn: created, + note: Value(note), + ), + ); + return id; + } + + /// All live sales, newest first (for the Sales screen). + Stream> watchSales() => (_db.select(_db.sales) + ..where((s) => s.isDeleted.equals(false)) + ..orderBy([(s) => OrderingTerm.desc(s.soldOn)])) + .watch(); + + /// The sales recorded against one variety. + Stream> watchSalesForVariety(String varietyId) => + (_db.select(_db.sales) + ..where( + (s) => s.varietyId.equals(varietyId) & s.isDeleted.equals(false), + ) + ..orderBy([(s) => OrderingTerm.desc(s.soldOn)])) + .watch(); + + /// Soft-deletes a sale (tombstone, so it syncs as a removal). + Future deleteSale(String id) async { + final (_, updated) = await _stamp(); + await (_db.update(_db.sales)..where((s) => s.id.equals(id))).write( + SalesCompanion( + isDeleted: const Value(true), + updatedAt: Value(updated), + lastAuthor: Value(nodeId), + ), + ); + } + /// Snapshots the live inventory (tombstones excluded) for the interchange /// export — data-model §7. Includes photo bytes; the JSON codec embeds them /// as base64 and the CSV codec ignores them. @@ -1819,6 +1877,9 @@ class VarietyRepository { plantares: await (_db.select( _db.plantares, )..where((p) => p.isDeleted.equals(false))).get(), + sales: await (_db.select( + _db.sales, + )..where((s) => s.isDeleted.equals(false))).get(), ); } @@ -1842,6 +1903,7 @@ class VarietyRepository { movements: await _db.select(_db.movements).get(), parties: await _db.select(_db.parties).get(), plantares: await _db.select(_db.plantares).get(), + sales: await _db.select(_db.sales).get(), // attachments intentionally omitted — photos don't ride the sync wire. ); } @@ -1942,6 +2004,14 @@ class VarietyRepository { updatedAtOf: (r) => r.updatedAt, reconciler: reconciler, ); + summary += await _importMutableRows( + table: _db.sales, + idColumn: _db.sales.id, + rows: snapshot.sales, + idOf: (r) => r.id, + updatedAtOf: (r) => r.updatedAt, + reconciler: reconciler, + ); summary += await _importMovements(snapshot.movements, reconciler); }); @@ -1955,6 +2025,7 @@ class VarietyRepository { for (final p in snapshot.parties) p.updatedAt, for (final a in snapshot.attachments) a.updatedAt, for (final pl in snapshot.plantares) pl.updatedAt, + for (final s in snapshot.sales) s.updatedAt, ]); if (maxIncoming != null) { _clock = _clock.receiveEvent(maxIncoming, _now()); diff --git a/apps/app_seeds/lib/db/database.dart b/apps/app_seeds/lib/db/database.dart index 0c36ef5..0dc022c 100644 --- a/apps/app_seeds/lib/db/database.dart +++ b/apps/app_seeds/lib/db/database.dart @@ -23,6 +23,7 @@ part 'database.g.dart'; Attachments, ExternalLinks, Plantares, + Sales, ], ) class AppDatabase extends _$AppDatabase { @@ -30,7 +31,7 @@ class AppDatabase extends _$AppDatabase { /// Current schema version; also stamped into interchange exports so an /// importer knows which app generation wrote the file (data-model §7). - static const int currentSchemaVersion = 9; + static const int currentSchemaVersion = 10; @override int get schemaVersion => currentSchemaVersion; @@ -146,6 +147,12 @@ class AppDatabase extends _$AppDatabase { await m.createTable(plantares); } } + // v10: Sales — recorded seed sales (separate from gift/Plantare). Guarded. + if (from < 10) { + if (!await _hasTable('sales')) { + await m.createTable(sales); + } + } }, ); diff --git a/apps/app_seeds/lib/db/database.g.dart b/apps/app_seeds/lib/db/database.g.dart index 842928f..c9a1d6c 100644 --- a/apps/app_seeds/lib/db/database.g.dart +++ b/apps/app_seeds/lib/db/database.g.dart @@ -9395,6 +9395,784 @@ class PlantaresCompanion extends UpdateCompanion { } } +class $SalesTable extends Sales with TableInfo<$SalesTable, Sale> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $SalesTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); + @override + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _updatedAtMeta = const VerificationMeta( + 'updatedAt', + ); + @override + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _lastAuthorMeta = const VerificationMeta( + 'lastAuthor', + ); + @override + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _isDeletedMeta = const VerificationMeta( + 'isDeleted', + ); + @override + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_deleted" IN (0, 1))', + ), + defaultValue: const Constant(false), + ); + static const VerificationMeta _schemaRowVersionMeta = const VerificationMeta( + 'schemaRowVersion', + ); + @override + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(1), + ); + static const VerificationMeta _varietyIdMeta = const VerificationMeta( + 'varietyId', + ); + @override + late final GeneratedColumn varietyId = GeneratedColumn( + 'variety_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + late final GeneratedColumnWithTypeConverter direction = + GeneratedColumn( + 'direction', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ).withConverter($SalesTable.$converterdirection); + static const VerificationMeta _counterpartyMeta = const VerificationMeta( + 'counterparty', + ); + @override + late final GeneratedColumn counterparty = GeneratedColumn( + 'counterparty', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _amountMeta = const VerificationMeta('amount'); + @override + late final GeneratedColumn amount = GeneratedColumn( + 'amount', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + ); + static const VerificationMeta _currencyMeta = const VerificationMeta( + 'currency', + ); + @override + late final GeneratedColumn currency = GeneratedColumn( + 'currency', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _soldOnMeta = const VerificationMeta('soldOn'); + @override + late final GeneratedColumn soldOn = GeneratedColumn( + 'sold_on', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _noteMeta = const VerificationMeta('note'); + @override + late final GeneratedColumn note = GeneratedColumn( + 'note', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + varietyId, + direction, + counterparty, + amount, + currency, + soldOn, + note, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'sales'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('updated_at')) { + context.handle( + _updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta), + ); + } else if (isInserting) { + context.missing(_updatedAtMeta); + } + if (data.containsKey('last_author')) { + context.handle( + _lastAuthorMeta, + lastAuthor.isAcceptableOrUnknown(data['last_author']!, _lastAuthorMeta), + ); + } else if (isInserting) { + context.missing(_lastAuthorMeta); + } + if (data.containsKey('is_deleted')) { + context.handle( + _isDeletedMeta, + isDeleted.isAcceptableOrUnknown(data['is_deleted']!, _isDeletedMeta), + ); + } + if (data.containsKey('schema_row_version')) { + context.handle( + _schemaRowVersionMeta, + schemaRowVersion.isAcceptableOrUnknown( + data['schema_row_version']!, + _schemaRowVersionMeta, + ), + ); + } + if (data.containsKey('variety_id')) { + context.handle( + _varietyIdMeta, + varietyId.isAcceptableOrUnknown(data['variety_id']!, _varietyIdMeta), + ); + } + if (data.containsKey('counterparty')) { + context.handle( + _counterpartyMeta, + counterparty.isAcceptableOrUnknown( + data['counterparty']!, + _counterpartyMeta, + ), + ); + } + if (data.containsKey('amount')) { + context.handle( + _amountMeta, + amount.isAcceptableOrUnknown(data['amount']!, _amountMeta), + ); + } + if (data.containsKey('currency')) { + context.handle( + _currencyMeta, + currency.isAcceptableOrUnknown(data['currency']!, _currencyMeta), + ); + } + if (data.containsKey('sold_on')) { + context.handle( + _soldOnMeta, + soldOn.isAcceptableOrUnknown(data['sold_on']!, _soldOnMeta), + ); + } else if (isInserting) { + context.missing(_soldOnMeta); + } + if (data.containsKey('note')) { + context.handle( + _noteMeta, + note.isAcceptableOrUnknown(data['note']!, _noteMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + Sale map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return Sale( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at'], + )!, + updatedAt: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}updated_at'], + )!, + lastAuthor: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}last_author'], + )!, + isDeleted: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_deleted'], + )!, + schemaRowVersion: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}schema_row_version'], + )!, + varietyId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}variety_id'], + ), + direction: $SalesTable.$converterdirection.fromSql( + attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}direction'], + )!, + ), + counterparty: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}counterparty'], + ), + amount: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}amount'], + ), + currency: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}currency'], + ), + soldOn: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}sold_on'], + )!, + note: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}note'], + ), + ); + } + + @override + $SalesTable createAlias(String alias) { + return $SalesTable(attachedDatabase, alias); + } + + static JsonTypeConverter2 $converterdirection = + const EnumNameConverter(SaleDirection.values); +} + +class Sale extends DataClass implements Insertable { + final String id; + final int createdAt; + final String updatedAt; + final String lastAuthor; + final bool isDeleted; + final int schemaRowVersion; + + /// The seed sold/bought. Nullable so a sale can be jotted before it's linked + /// to a catalogued variety. + final String? varietyId; + + /// Whether I sold or I bought. + final SaleDirection direction; + + /// The other party as a human name (v1). + final String? counterparty; + + /// Price paid. Nullable — a barter-ish "sale" recorded before a figure is set. + final double? amount; + + /// The currency, free text: "€", "Ğ1", "horas", a local currency name. Never + /// assumed — the seed world uses many (sharing-model §6). + final String? currency; + + /// When the sale happened (ms since epoch). + final int soldOn; + final String? note; + const Sale({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.lastAuthor, + required this.isDeleted, + required this.schemaRowVersion, + this.varietyId, + required this.direction, + this.counterparty, + this.amount, + this.currency, + required this.soldOn, + this.note, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['last_author'] = Variable(lastAuthor); + map['is_deleted'] = Variable(isDeleted); + map['schema_row_version'] = Variable(schemaRowVersion); + if (!nullToAbsent || varietyId != null) { + map['variety_id'] = Variable(varietyId); + } + { + map['direction'] = Variable( + $SalesTable.$converterdirection.toSql(direction), + ); + } + if (!nullToAbsent || counterparty != null) { + map['counterparty'] = Variable(counterparty); + } + if (!nullToAbsent || amount != null) { + map['amount'] = Variable(amount); + } + if (!nullToAbsent || currency != null) { + map['currency'] = Variable(currency); + } + map['sold_on'] = Variable(soldOn); + if (!nullToAbsent || note != null) { + map['note'] = Variable(note); + } + return map; + } + + SalesCompanion toCompanion(bool nullToAbsent) { + return SalesCompanion( + id: Value(id), + createdAt: Value(createdAt), + updatedAt: Value(updatedAt), + lastAuthor: Value(lastAuthor), + isDeleted: Value(isDeleted), + schemaRowVersion: Value(schemaRowVersion), + varietyId: varietyId == null && nullToAbsent + ? const Value.absent() + : Value(varietyId), + direction: Value(direction), + counterparty: counterparty == null && nullToAbsent + ? const Value.absent() + : Value(counterparty), + amount: amount == null && nullToAbsent + ? const Value.absent() + : Value(amount), + currency: currency == null && nullToAbsent + ? const Value.absent() + : Value(currency), + soldOn: Value(soldOn), + note: note == null && nullToAbsent ? const Value.absent() : Value(note), + ); + } + + factory Sale.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Sale( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + lastAuthor: serializer.fromJson(json['lastAuthor']), + isDeleted: serializer.fromJson(json['isDeleted']), + schemaRowVersion: serializer.fromJson(json['schemaRowVersion']), + varietyId: serializer.fromJson(json['varietyId']), + direction: $SalesTable.$converterdirection.fromJson( + serializer.fromJson(json['direction']), + ), + counterparty: serializer.fromJson(json['counterparty']), + amount: serializer.fromJson(json['amount']), + currency: serializer.fromJson(json['currency']), + soldOn: serializer.fromJson(json['soldOn']), + note: serializer.fromJson(json['note']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'lastAuthor': serializer.toJson(lastAuthor), + 'isDeleted': serializer.toJson(isDeleted), + 'schemaRowVersion': serializer.toJson(schemaRowVersion), + 'varietyId': serializer.toJson(varietyId), + 'direction': serializer.toJson( + $SalesTable.$converterdirection.toJson(direction), + ), + 'counterparty': serializer.toJson(counterparty), + 'amount': serializer.toJson(amount), + 'currency': serializer.toJson(currency), + 'soldOn': serializer.toJson(soldOn), + 'note': serializer.toJson(note), + }; + } + + Sale copyWith({ + String? id, + int? createdAt, + String? updatedAt, + String? lastAuthor, + bool? isDeleted, + int? schemaRowVersion, + Value varietyId = const Value.absent(), + SaleDirection? direction, + Value counterparty = const Value.absent(), + Value amount = const Value.absent(), + Value currency = const Value.absent(), + int? soldOn, + Value note = const Value.absent(), + }) => Sale( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + varietyId: varietyId.present ? varietyId.value : this.varietyId, + direction: direction ?? this.direction, + counterparty: counterparty.present ? counterparty.value : this.counterparty, + amount: amount.present ? amount.value : this.amount, + currency: currency.present ? currency.value : this.currency, + soldOn: soldOn ?? this.soldOn, + note: note.present ? note.value : this.note, + ); + Sale copyWithCompanion(SalesCompanion data) { + return Sale( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + lastAuthor: data.lastAuthor.present + ? data.lastAuthor.value + : this.lastAuthor, + isDeleted: data.isDeleted.present ? data.isDeleted.value : this.isDeleted, + schemaRowVersion: data.schemaRowVersion.present + ? data.schemaRowVersion.value + : this.schemaRowVersion, + varietyId: data.varietyId.present ? data.varietyId.value : this.varietyId, + direction: data.direction.present ? data.direction.value : this.direction, + counterparty: data.counterparty.present + ? data.counterparty.value + : this.counterparty, + amount: data.amount.present ? data.amount.value : this.amount, + currency: data.currency.present ? data.currency.value : this.currency, + soldOn: data.soldOn.present ? data.soldOn.value : this.soldOn, + note: data.note.present ? data.note.value : this.note, + ); + } + + @override + String toString() { + return (StringBuffer('Sale(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('varietyId: $varietyId, ') + ..write('direction: $direction, ') + ..write('counterparty: $counterparty, ') + ..write('amount: $amount, ') + ..write('currency: $currency, ') + ..write('soldOn: $soldOn, ') + ..write('note: $note') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + varietyId, + direction, + counterparty, + amount, + currency, + soldOn, + note, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Sale && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.lastAuthor == this.lastAuthor && + other.isDeleted == this.isDeleted && + other.schemaRowVersion == this.schemaRowVersion && + other.varietyId == this.varietyId && + other.direction == this.direction && + other.counterparty == this.counterparty && + other.amount == this.amount && + other.currency == this.currency && + other.soldOn == this.soldOn && + other.note == this.note); +} + +class SalesCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value lastAuthor; + final Value isDeleted; + final Value schemaRowVersion; + final Value varietyId; + final Value direction; + final Value counterparty; + final Value amount; + final Value currency; + final Value soldOn; + final Value note; + final Value rowid; + const SalesCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.lastAuthor = const Value.absent(), + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + this.varietyId = const Value.absent(), + this.direction = const Value.absent(), + this.counterparty = const Value.absent(), + this.amount = const Value.absent(), + this.currency = const Value.absent(), + this.soldOn = const Value.absent(), + this.note = const Value.absent(), + this.rowid = const Value.absent(), + }); + SalesCompanion.insert({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + this.isDeleted = const Value.absent(), + this.schemaRowVersion = const Value.absent(), + this.varietyId = const Value.absent(), + required SaleDirection direction, + this.counterparty = const Value.absent(), + this.amount = const Value.absent(), + this.currency = const Value.absent(), + required int soldOn, + this.note = const Value.absent(), + this.rowid = const Value.absent(), + }) : id = Value(id), + createdAt = Value(createdAt), + updatedAt = Value(updatedAt), + lastAuthor = Value(lastAuthor), + direction = Value(direction), + soldOn = Value(soldOn); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? lastAuthor, + Expression? isDeleted, + Expression? schemaRowVersion, + Expression? varietyId, + Expression? direction, + Expression? counterparty, + Expression? amount, + Expression? currency, + Expression? soldOn, + Expression? note, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (lastAuthor != null) 'last_author': lastAuthor, + if (isDeleted != null) 'is_deleted': isDeleted, + if (schemaRowVersion != null) 'schema_row_version': schemaRowVersion, + if (varietyId != null) 'variety_id': varietyId, + if (direction != null) 'direction': direction, + if (counterparty != null) 'counterparty': counterparty, + if (amount != null) 'amount': amount, + if (currency != null) 'currency': currency, + if (soldOn != null) 'sold_on': soldOn, + if (note != null) 'note': note, + if (rowid != null) 'rowid': rowid, + }); + } + + SalesCompanion copyWith({ + Value? id, + Value? createdAt, + Value? updatedAt, + Value? lastAuthor, + Value? isDeleted, + Value? schemaRowVersion, + Value? varietyId, + Value? direction, + Value? counterparty, + Value? amount, + Value? currency, + Value? soldOn, + Value? note, + Value? rowid, + }) { + return SalesCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastAuthor: lastAuthor ?? this.lastAuthor, + isDeleted: isDeleted ?? this.isDeleted, + schemaRowVersion: schemaRowVersion ?? this.schemaRowVersion, + varietyId: varietyId ?? this.varietyId, + direction: direction ?? this.direction, + counterparty: counterparty ?? this.counterparty, + amount: amount ?? this.amount, + currency: currency ?? this.currency, + soldOn: soldOn ?? this.soldOn, + note: note ?? this.note, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (lastAuthor.present) { + map['last_author'] = Variable(lastAuthor.value); + } + if (isDeleted.present) { + map['is_deleted'] = Variable(isDeleted.value); + } + if (schemaRowVersion.present) { + map['schema_row_version'] = Variable(schemaRowVersion.value); + } + if (varietyId.present) { + map['variety_id'] = Variable(varietyId.value); + } + if (direction.present) { + map['direction'] = Variable( + $SalesTable.$converterdirection.toSql(direction.value), + ); + } + if (counterparty.present) { + map['counterparty'] = Variable(counterparty.value); + } + if (amount.present) { + map['amount'] = Variable(amount.value); + } + if (currency.present) { + map['currency'] = Variable(currency.value); + } + if (soldOn.present) { + map['sold_on'] = Variable(soldOn.value); + } + if (note.present) { + map['note'] = Variable(note.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('SalesCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastAuthor: $lastAuthor, ') + ..write('isDeleted: $isDeleted, ') + ..write('schemaRowVersion: $schemaRowVersion, ') + ..write('varietyId: $varietyId, ') + ..write('direction: $direction, ') + ..write('counterparty: $counterparty, ') + ..write('amount: $amount, ') + ..write('currency: $currency, ') + ..write('soldOn: $soldOn, ') + ..write('note: $note, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + abstract class _$AppDatabase extends GeneratedDatabase { _$AppDatabase(QueryExecutor e) : super(e); $AppDatabaseManager get managers => $AppDatabaseManager(this); @@ -9416,6 +10194,7 @@ abstract class _$AppDatabase extends GeneratedDatabase { late final $AttachmentsTable attachments = $AttachmentsTable(this); late final $ExternalLinksTable externalLinks = $ExternalLinksTable(this); late final $PlantaresTable plantares = $PlantaresTable(this); + late final $SalesTable sales = $SalesTable(this); @override Iterable> get allTables => allSchemaEntities.whereType>(); @@ -9433,6 +10212,7 @@ abstract class _$AppDatabase extends GeneratedDatabase { attachments, externalLinks, plantares, + sales, ]; } @@ -13794,6 +14574,358 @@ typedef $$PlantaresTableProcessedTableManager = Plantare, PrefetchHooks Function() >; +typedef $$SalesTableCreateCompanionBuilder = + SalesCompanion Function({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted, + Value schemaRowVersion, + Value varietyId, + required SaleDirection direction, + Value counterparty, + Value amount, + Value currency, + required int soldOn, + Value note, + Value rowid, + }); +typedef $$SalesTableUpdateCompanionBuilder = + SalesCompanion Function({ + Value id, + Value createdAt, + Value updatedAt, + Value lastAuthor, + Value isDeleted, + Value schemaRowVersion, + Value varietyId, + Value direction, + Value counterparty, + Value amount, + Value currency, + Value soldOn, + Value note, + Value rowid, + }); + +class $$SalesTableFilterComposer extends Composer<_$AppDatabase, $SalesTable> { + $$SalesTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get varietyId => $composableBuilder( + column: $table.varietyId, + builder: (column) => ColumnFilters(column), + ); + + ColumnWithTypeConverterFilters + get direction => $composableBuilder( + column: $table.direction, + builder: (column) => ColumnWithTypeConverterFilters(column), + ); + + ColumnFilters get counterparty => $composableBuilder( + column: $table.counterparty, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get amount => $composableBuilder( + column: $table.amount, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get currency => $composableBuilder( + column: $table.currency, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get soldOn => $composableBuilder( + column: $table.soldOn, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get note => $composableBuilder( + column: $table.note, + builder: (column) => ColumnFilters(column), + ); +} + +class $$SalesTableOrderingComposer + extends Composer<_$AppDatabase, $SalesTable> { + $$SalesTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get updatedAt => $composableBuilder( + column: $table.updatedAt, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get isDeleted => $composableBuilder( + column: $table.isDeleted, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get varietyId => $composableBuilder( + column: $table.varietyId, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get direction => $composableBuilder( + column: $table.direction, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get counterparty => $composableBuilder( + column: $table.counterparty, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get amount => $composableBuilder( + column: $table.amount, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get currency => $composableBuilder( + column: $table.currency, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get soldOn => $composableBuilder( + column: $table.soldOn, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get note => $composableBuilder( + column: $table.note, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$SalesTableAnnotationComposer + extends Composer<_$AppDatabase, $SalesTable> { + $$SalesTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + + GeneratedColumn get updatedAt => + $composableBuilder(column: $table.updatedAt, builder: (column) => column); + + GeneratedColumn get lastAuthor => $composableBuilder( + column: $table.lastAuthor, + builder: (column) => column, + ); + + GeneratedColumn get isDeleted => + $composableBuilder(column: $table.isDeleted, builder: (column) => column); + + GeneratedColumn get schemaRowVersion => $composableBuilder( + column: $table.schemaRowVersion, + builder: (column) => column, + ); + + GeneratedColumn get varietyId => + $composableBuilder(column: $table.varietyId, builder: (column) => column); + + GeneratedColumnWithTypeConverter get direction => + $composableBuilder(column: $table.direction, builder: (column) => column); + + GeneratedColumn get counterparty => $composableBuilder( + column: $table.counterparty, + builder: (column) => column, + ); + + GeneratedColumn get amount => + $composableBuilder(column: $table.amount, builder: (column) => column); + + GeneratedColumn get currency => + $composableBuilder(column: $table.currency, builder: (column) => column); + + GeneratedColumn get soldOn => + $composableBuilder(column: $table.soldOn, builder: (column) => column); + + GeneratedColumn get note => + $composableBuilder(column: $table.note, builder: (column) => column); +} + +class $$SalesTableTableManager + extends + RootTableManager< + _$AppDatabase, + $SalesTable, + Sale, + $$SalesTableFilterComposer, + $$SalesTableOrderingComposer, + $$SalesTableAnnotationComposer, + $$SalesTableCreateCompanionBuilder, + $$SalesTableUpdateCompanionBuilder, + (Sale, BaseReferences<_$AppDatabase, $SalesTable, Sale>), + Sale, + PrefetchHooks Function() + > { + $$SalesTableTableManager(_$AppDatabase db, $SalesTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$SalesTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$SalesTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$SalesTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value createdAt = const Value.absent(), + Value updatedAt = const Value.absent(), + Value lastAuthor = const Value.absent(), + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + Value varietyId = const Value.absent(), + Value direction = const Value.absent(), + Value counterparty = const Value.absent(), + Value amount = const Value.absent(), + Value currency = const Value.absent(), + Value soldOn = const Value.absent(), + Value note = const Value.absent(), + Value rowid = const Value.absent(), + }) => SalesCompanion( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + varietyId: varietyId, + direction: direction, + counterparty: counterparty, + amount: amount, + currency: currency, + soldOn: soldOn, + note: note, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String id, + required int createdAt, + required String updatedAt, + required String lastAuthor, + Value isDeleted = const Value.absent(), + Value schemaRowVersion = const Value.absent(), + Value varietyId = const Value.absent(), + required SaleDirection direction, + Value counterparty = const Value.absent(), + Value amount = const Value.absent(), + Value currency = const Value.absent(), + required int soldOn, + Value note = const Value.absent(), + Value rowid = const Value.absent(), + }) => SalesCompanion.insert( + id: id, + createdAt: createdAt, + updatedAt: updatedAt, + lastAuthor: lastAuthor, + isDeleted: isDeleted, + schemaRowVersion: schemaRowVersion, + varietyId: varietyId, + direction: direction, + counterparty: counterparty, + amount: amount, + currency: currency, + soldOn: soldOn, + note: note, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + ), + ); +} + +typedef $$SalesTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $SalesTable, + Sale, + $$SalesTableFilterComposer, + $$SalesTableOrderingComposer, + $$SalesTableAnnotationComposer, + $$SalesTableCreateCompanionBuilder, + $$SalesTableUpdateCompanionBuilder, + (Sale, BaseReferences<_$AppDatabase, $SalesTable, Sale>), + Sale, + PrefetchHooks Function() + >; class $AppDatabaseManager { final _$AppDatabase _db; @@ -13824,4 +14956,6 @@ class $AppDatabaseManager { $$ExternalLinksTableTableManager(_db, _db.externalLinks); $$PlantaresTableTableManager get plantares => $$PlantaresTableTableManager(_db, _db.plantares); + $$SalesTableTableManager get sales => + $$SalesTableTableManager(_db, _db.sales); } diff --git a/apps/app_seeds/lib/db/enums.dart b/apps/app_seeds/lib/db/enums.dart index 5227357..4617309 100644 --- a/apps/app_seeds/lib/db/enums.dart +++ b/apps/app_seeds/lib/db/enums.dart @@ -101,3 +101,8 @@ enum PlantareDirection { /// Lifecycle of a Plantare. Framed as a promise, not a debt (data-model §2.7): /// `forgiven` (not "defaulted") when it's let go. enum PlantareStatus { open, returned, forgiven } + +/// Direction of a recorded seed Sale, seen from this app's owner. A sale is a +/// SEPARATE model from a gift or a Plantare — seed for money (any currency: +/// €, Ğ1, a local/time currency…). No commission is ever taken on seeds. +enum SaleDirection { iSold, iBought } diff --git a/apps/app_seeds/lib/db/tables.dart b/apps/app_seeds/lib/db/tables.dart index e51b392..064ae42 100644 --- a/apps/app_seeds/lib/db/tables.dart +++ b/apps/app_seeds/lib/db/tables.dart @@ -212,6 +212,34 @@ class Plantares extends Table with SyncColumns { TextColumn get note => text().nullable()(); } +/// A recorded seed Sale — seed for money (data-model §2.8/sharing-model §6). A +/// SEPARATE model from a gift or a Plantare: a completed exchange with a price +/// in ANY currency (€, Ğ1, a local/time currency). Local-first ledger; the +/// cross-party/receipt form is a later social-layer concern. +class Sales extends Table with SyncColumns { + /// The seed sold/bought. Nullable so a sale can be jotted before it's linked + /// to a catalogued variety. + TextColumn get varietyId => text().nullable()(); // → Variety + + /// Whether I sold or I bought. + TextColumn get direction => textEnum()(); + + /// The other party as a human name (v1). + TextColumn get counterparty => text().nullable()(); + + /// Price paid. Nullable — a barter-ish "sale" recorded before a figure is set. + RealColumn get amount => real().nullable()(); + + /// The currency, free text: "€", "Ğ1", "horas", a local currency name. Never + /// assumed — the seed world uses many (sharing-model §6). + TextColumn get currency => text().nullable()(); + + /// When the sale happened (ms since epoch). + IntColumn get soldOn => integer()(); + + TextColumn get note => text().nullable()(); +} + /// Any pasted URL (Wikipedia, forum…). Polymorphic parent. class ExternalLinks extends Table with SyncColumns { TextColumn get parentType => textEnum()(); diff --git a/apps/app_seeds/lib/i18n/ast.i18n.json b/apps/app_seeds/lib/i18n/ast.i18n.json index 0eebba4..f0d6b73 100644 --- a/apps/app_seeds/lib/i18n/ast.i18n.json +++ b/apps/app_seeds/lib/i18n/ast.i18n.json @@ -37,6 +37,7 @@ "wishlist": "Llista de deseos", "following": "Siguiendo", "plantares": "Plantares", + "sales": "Ventes", "settings": "Axustes" }, "settings": { @@ -577,5 +578,23 @@ "openSection": "Pendientes", "settledSection": "Fechos", "removeConfirm": "¿Quitar esti compromisu?" + }, + "sale": { + "title": "Ventes", + "help": "Rexistra semilla vendida o mercada — dineru, Ğ1 o cualquier moneda. Un modelu aparte del regalu y del Plantare. Enxamás se cobra comisión poles semilles.", + "add": "Rexistrar venta", + "empty": "Entá nun hai ventes. Anota equí lo que vendes o merques.", + "iSold": "Vendí", + "iBought": "Mercué", + "direction": "¿Vendes o merques?", + "counterparty": "¿Con quién?", + "counterpartyHint": "Una persona o un coleutivu (opcional)", + "amount": "Importe", + "currency": "Moneda", + "currencyHint": "€, Ğ1, hores… (opcional)", + "note": "Nota (opcional)", + "save": "Guardar", + "delete": "Quitar", + "removeConfirm": "¿Quitar esta venta?" } } diff --git a/apps/app_seeds/lib/i18n/en.i18n.json b/apps/app_seeds/lib/i18n/en.i18n.json index e4462cf..329c8a3 100644 --- a/apps/app_seeds/lib/i18n/en.i18n.json +++ b/apps/app_seeds/lib/i18n/en.i18n.json @@ -38,6 +38,7 @@ "wishlist": "Wishlist", "following": "Following", "plantares": "Plantares", + "sales": "Sales", "settings": "Settings" }, "settings": { @@ -580,5 +581,23 @@ "openSection": "Open", "settledSection": "Done", "removeConfirm": "Remove this commitment?" + }, + "sale": { + "title": "Sales", + "help": "Record seed you sold or bought — money, Ğ1, or any currency. A separate model from a gift or a Plantare. No commission is ever taken on seeds.", + "add": "Record a sale", + "empty": "No sales yet. Note here what you sell or buy.", + "iSold": "I sold", + "iBought": "I bought", + "direction": "Sold or bought?", + "counterparty": "With whom?", + "counterpartyHint": "A person or a collective (optional)", + "amount": "Amount", + "currency": "Currency", + "currencyHint": "€, Ğ1, hours… (optional)", + "note": "Note (optional)", + "save": "Save", + "delete": "Remove", + "removeConfirm": "Remove this sale?" } } diff --git a/apps/app_seeds/lib/i18n/es.i18n.json b/apps/app_seeds/lib/i18n/es.i18n.json index b627b0c..0f2fc09 100644 --- a/apps/app_seeds/lib/i18n/es.i18n.json +++ b/apps/app_seeds/lib/i18n/es.i18n.json @@ -38,6 +38,7 @@ "wishlist": "Lista de deseos", "following": "Siguiendo", "plantares": "Plantares", + "sales": "Ventas", "settings": "Ajustes" }, "settings": { @@ -579,5 +580,23 @@ "openSection": "Pendientes", "settledSection": "Hechos", "removeConfirm": "¿Quitar este compromiso?" + }, + "sale": { + "title": "Ventas", + "help": "Registra semilla vendida o comprada — dinero, Ğ1 o cualquier moneda. Un modelo aparte del regalo y del Plantare. Nunca se cobra comisión por las semillas.", + "add": "Registrar venta", + "empty": "Aún no hay ventas. Anota aquí lo que vendes o compras.", + "iSold": "Vendí", + "iBought": "Compré", + "direction": "¿Vendes o compras?", + "counterparty": "¿Con quién?", + "counterpartyHint": "Una persona o un colectivo (opcional)", + "amount": "Importe", + "currency": "Moneda", + "currencyHint": "€, Ğ1, horas… (opcional)", + "note": "Nota (opcional)", + "save": "Guardar", + "delete": "Quitar", + "removeConfirm": "¿Quitar esta venta?" } } diff --git a/apps/app_seeds/lib/i18n/pt.i18n.json b/apps/app_seeds/lib/i18n/pt.i18n.json index 322f6fc..650cb3a 100644 --- a/apps/app_seeds/lib/i18n/pt.i18n.json +++ b/apps/app_seeds/lib/i18n/pt.i18n.json @@ -38,6 +38,7 @@ "wishlist": "Lista de desejos", "following": "A seguir", "plantares": "Plantares", + "sales": "Vendas", "settings": "Definições" }, "settings": { @@ -576,5 +577,23 @@ "openSection": "Pendentes", "settledSection": "Feitos", "removeConfirm": "Remover este compromisso?" + }, + "sale": { + "title": "Vendas", + "help": "Regista semente vendida ou comprada — dinheiro, Ğ1 ou qualquer moeda. Um modelo separado do presente e do Plantare. Nunca se cobra comissão pelas sementes.", + "add": "Registar venda", + "empty": "Ainda não há vendas. Anota aqui o que vendes ou compras.", + "iSold": "Vendi", + "iBought": "Comprei", + "direction": "Vendes ou compras?", + "counterparty": "Com quem?", + "counterpartyHint": "Uma pessoa ou um coletivo (opcional)", + "amount": "Montante", + "currency": "Moeda", + "currencyHint": "€, Ğ1, horas… (opcional)", + "note": "Nota (opcional)", + "save": "Guardar", + "delete": "Remover", + "removeConfirm": "Remover esta venda?" } } diff --git a/apps/app_seeds/lib/i18n/strings.g.dart b/apps/app_seeds/lib/i18n/strings.g.dart index 3c5dc97..edcc89a 100644 --- a/apps/app_seeds/lib/i18n/strings.g.dart +++ b/apps/app_seeds/lib/i18n/strings.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 4 -/// Strings: 1760 (440 per locale) +/// Strings: 1828 (457 per locale) /// -/// Built on 2026-07-11 at 00:04 UTC +/// Built on 2026-07-11 at 00:20 UTC // coverage:ignore-file // ignore_for_file: type=lint, unused_import diff --git a/apps/app_seeds/lib/i18n/strings_ast.g.dart b/apps/app_seeds/lib/i18n/strings_ast.g.dart index 930706d..e8f643d 100644 --- a/apps/app_seeds/lib/i18n/strings_ast.g.dart +++ b/apps/app_seeds/lib/i18n/strings_ast.g.dart @@ -78,6 +78,7 @@ class TranslationsAst extends Translations with BaseTranslations 'Llista de deseos'; @override String get following => 'Siguiendo'; @override String get plantares => 'Plantares'; + @override String get sales => 'Ventes'; @override String get settings => 'Axustes'; } @@ -839,6 +841,31 @@ class _Translations$plantare$ast extends Translations$plantare$en { @override String get removeConfirm => '¿Quitar esti compromisu?'; } +// Path: sale +class _Translations$sale$ast extends Translations$sale$en { + _Translations$sale$ast._(TranslationsAst root) : this._root = root, super.internal(root); + + final TranslationsAst _root; // ignore: unused_field + + // Translations + @override String get title => 'Ventes'; + @override String get help => 'Rexistra semilla vendida o mercada — dineru, Ğ1 o cualquier moneda. Un modelu aparte del regalu y del Plantare. Enxamás se cobra comisión poles semilles.'; + @override String get add => 'Rexistrar venta'; + @override String get empty => 'Entá nun hai ventes. Anota equí lo que vendes o merques.'; + @override String get iSold => 'Vendí'; + @override String get iBought => 'Mercué'; + @override String get direction => '¿Vendes o merques?'; + @override String get counterparty => '¿Con quién?'; + @override String get counterpartyHint => 'Una persona o un coleutivu (opcional)'; + @override String get amount => 'Importe'; + @override String get currency => 'Moneda'; + @override String get currencyHint => '€, Ğ1, hores… (opcional)'; + @override String get note => 'Nota (opcional)'; + @override String get save => 'Guardar'; + @override String get delete => 'Quitar'; + @override String get removeConfirm => '¿Quitar esta venta?'; +} + // Path: intro.slides class _Translations$intro$slides$ast extends Translations$intro$slides$en { _Translations$intro$slides$ast._(TranslationsAst root) : this._root = root, super.internal(root); @@ -1207,6 +1234,7 @@ extension on TranslationsAst { 'menu.wishlist' => 'Llista de deseos', 'menu.following' => 'Siguiendo', 'menu.plantares' => 'Plantares', + 'menu.sales' => 'Ventes', 'menu.settings' => 'Axustes', 'settings.language' => 'Llingua', 'settings.systemLanguage' => 'Llingua del sistema', @@ -1619,6 +1647,22 @@ extension on TranslationsAst { 'plantare.openSection' => 'Pendientes', 'plantare.settledSection' => 'Fechos', 'plantare.removeConfirm' => '¿Quitar esti compromisu?', + 'sale.title' => 'Ventes', + 'sale.help' => 'Rexistra semilla vendida o mercada — dineru, Ğ1 o cualquier moneda. Un modelu aparte del regalu y del Plantare. Enxamás se cobra comisión poles semilles.', + 'sale.add' => 'Rexistrar venta', + 'sale.empty' => 'Entá nun hai ventes. Anota equí lo que vendes o merques.', + 'sale.iSold' => 'Vendí', + 'sale.iBought' => 'Mercué', + 'sale.direction' => '¿Vendes o merques?', + 'sale.counterparty' => '¿Con quién?', + 'sale.counterpartyHint' => 'Una persona o un coleutivu (opcional)', + 'sale.amount' => 'Importe', + 'sale.currency' => 'Moneda', + 'sale.currencyHint' => '€, Ğ1, hores… (opcional)', + 'sale.note' => 'Nota (opcional)', + 'sale.save' => 'Guardar', + 'sale.delete' => 'Quitar', + 'sale.removeConfirm' => '¿Quitar esta venta?', _ => null, }; } diff --git a/apps/app_seeds/lib/i18n/strings_en.g.dart b/apps/app_seeds/lib/i18n/strings_en.g.dart index 68ea9ef..60af4ee 100644 --- a/apps/app_seeds/lib/i18n/strings_en.g.dart +++ b/apps/app_seeds/lib/i18n/strings_en.g.dart @@ -79,6 +79,7 @@ class Translations with BaseTranslations { late final Translations$wot$en wot = Translations$wot$en.internal(_root); late final Translations$notifications$en notifications = Translations$notifications$en.internal(_root); late final Translations$plantare$en plantare = Translations$plantare$en.internal(_root); + late final Translations$sale$en sale = Translations$sale$en.internal(_root); } // Path: app @@ -218,6 +219,9 @@ class Translations$menu$en { /// en: 'Plantares' String get plantares => 'Plantares'; + /// en: 'Sales' + String get sales => 'Sales'; + /// en: 'Settings' String get settings => 'Settings'; } @@ -1590,6 +1594,63 @@ class Translations$plantare$en { String get removeConfirm => 'Remove this commitment?'; } +// Path: sale +class Translations$sale$en { + Translations$sale$en.internal(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Sales' + String get title => 'Sales'; + + /// en: 'Record seed you sold or bought — money, Ğ1, or any currency. A separate model from a gift or a Plantare. No commission is ever taken on seeds.' + String get help => 'Record seed you sold or bought — money, Ğ1, or any currency. A separate model from a gift or a Plantare. No commission is ever taken on seeds.'; + + /// en: 'Record a sale' + String get add => 'Record a sale'; + + /// en: 'No sales yet. Note here what you sell or buy.' + String get empty => 'No sales yet. Note here what you sell or buy.'; + + /// en: 'I sold' + String get iSold => 'I sold'; + + /// en: 'I bought' + String get iBought => 'I bought'; + + /// en: 'Sold or bought?' + String get direction => 'Sold or bought?'; + + /// en: 'With whom?' + String get counterparty => 'With whom?'; + + /// en: 'A person or a collective (optional)' + String get counterpartyHint => 'A person or a collective (optional)'; + + /// en: 'Amount' + String get amount => 'Amount'; + + /// en: 'Currency' + String get currency => 'Currency'; + + /// en: '€, Ğ1, hours… (optional)' + String get currencyHint => '€, Ğ1, hours… (optional)'; + + /// en: 'Note (optional)' + String get note => 'Note (optional)'; + + /// en: 'Save' + String get save => 'Save'; + + /// en: 'Remove' + String get delete => 'Remove'; + + /// en: 'Remove this sale?' + String get removeConfirm => 'Remove this sale?'; +} + // Path: intro.slides class Translations$intro$slides$en { Translations$intro$slides$en.internal(this._root); @@ -2075,6 +2136,7 @@ extension on Translations { 'menu.wishlist' => 'Wishlist', 'menu.following' => 'Following', 'menu.plantares' => 'Plantares', + 'menu.sales' => 'Sales', 'menu.settings' => 'Settings', 'settings.language' => 'Language', 'settings.systemLanguage' => 'System language', @@ -2489,6 +2551,22 @@ extension on Translations { 'plantare.openSection' => 'Open', 'plantare.settledSection' => 'Done', 'plantare.removeConfirm' => 'Remove this commitment?', + 'sale.title' => 'Sales', + 'sale.help' => 'Record seed you sold or bought — money, Ğ1, or any currency. A separate model from a gift or a Plantare. No commission is ever taken on seeds.', + 'sale.add' => 'Record a sale', + 'sale.empty' => 'No sales yet. Note here what you sell or buy.', + 'sale.iSold' => 'I sold', + 'sale.iBought' => 'I bought', + 'sale.direction' => 'Sold or bought?', + 'sale.counterparty' => 'With whom?', + 'sale.counterpartyHint' => 'A person or a collective (optional)', + 'sale.amount' => 'Amount', + 'sale.currency' => 'Currency', + 'sale.currencyHint' => '€, Ğ1, hours… (optional)', + 'sale.note' => 'Note (optional)', + 'sale.save' => 'Save', + 'sale.delete' => 'Remove', + 'sale.removeConfirm' => 'Remove this sale?', _ => null, }; } diff --git a/apps/app_seeds/lib/i18n/strings_es.g.dart b/apps/app_seeds/lib/i18n/strings_es.g.dart index 5c12cbc..8a0a9f3 100644 --- a/apps/app_seeds/lib/i18n/strings_es.g.dart +++ b/apps/app_seeds/lib/i18n/strings_es.g.dart @@ -78,6 +78,7 @@ class TranslationsEs extends Translations with BaseTranslations 'Lista de deseos'; @override String get following => 'Siguiendo'; @override String get plantares => 'Plantares'; + @override String get sales => 'Ventas'; @override String get settings => 'Ajustes'; } @@ -841,6 +843,31 @@ class _Translations$plantare$es extends Translations$plantare$en { @override String get removeConfirm => '¿Quitar este compromiso?'; } +// Path: sale +class _Translations$sale$es extends Translations$sale$en { + _Translations$sale$es._(TranslationsEs root) : this._root = root, super.internal(root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get title => 'Ventas'; + @override String get help => 'Registra semilla vendida o comprada — dinero, Ğ1 o cualquier moneda. Un modelo aparte del regalo y del Plantare. Nunca se cobra comisión por las semillas.'; + @override String get add => 'Registrar venta'; + @override String get empty => 'Aún no hay ventas. Anota aquí lo que vendes o compras.'; + @override String get iSold => 'Vendí'; + @override String get iBought => 'Compré'; + @override String get direction => '¿Vendes o compras?'; + @override String get counterparty => '¿Con quién?'; + @override String get counterpartyHint => 'Una persona o un colectivo (opcional)'; + @override String get amount => 'Importe'; + @override String get currency => 'Moneda'; + @override String get currencyHint => '€, Ğ1, horas… (opcional)'; + @override String get note => 'Nota (opcional)'; + @override String get save => 'Guardar'; + @override String get delete => 'Quitar'; + @override String get removeConfirm => '¿Quitar esta venta?'; +} + // Path: intro.slides class _Translations$intro$slides$es extends Translations$intro$slides$en { _Translations$intro$slides$es._(TranslationsEs root) : this._root = root, super.internal(root); @@ -1210,6 +1237,7 @@ extension on TranslationsEs { 'menu.wishlist' => 'Lista de deseos', 'menu.following' => 'Siguiendo', 'menu.plantares' => 'Plantares', + 'menu.sales' => 'Ventas', 'menu.settings' => 'Ajustes', 'settings.language' => 'Idioma', 'settings.systemLanguage' => 'Idioma del sistema', @@ -1623,6 +1651,22 @@ extension on TranslationsEs { 'plantare.openSection' => 'Pendientes', 'plantare.settledSection' => 'Hechos', 'plantare.removeConfirm' => '¿Quitar este compromiso?', + 'sale.title' => 'Ventas', + 'sale.help' => 'Registra semilla vendida o comprada — dinero, Ğ1 o cualquier moneda. Un modelo aparte del regalo y del Plantare. Nunca se cobra comisión por las semillas.', + 'sale.add' => 'Registrar venta', + 'sale.empty' => 'Aún no hay ventas. Anota aquí lo que vendes o compras.', + 'sale.iSold' => 'Vendí', + 'sale.iBought' => 'Compré', + 'sale.direction' => '¿Vendes o compras?', + 'sale.counterparty' => '¿Con quién?', + 'sale.counterpartyHint' => 'Una persona o un colectivo (opcional)', + 'sale.amount' => 'Importe', + 'sale.currency' => 'Moneda', + 'sale.currencyHint' => '€, Ğ1, horas… (opcional)', + 'sale.note' => 'Nota (opcional)', + 'sale.save' => 'Guardar', + 'sale.delete' => 'Quitar', + 'sale.removeConfirm' => '¿Quitar esta venta?', _ => null, }; } diff --git a/apps/app_seeds/lib/i18n/strings_pt.g.dart b/apps/app_seeds/lib/i18n/strings_pt.g.dart index 26c0e68..29144e5 100644 --- a/apps/app_seeds/lib/i18n/strings_pt.g.dart +++ b/apps/app_seeds/lib/i18n/strings_pt.g.dart @@ -78,6 +78,7 @@ class TranslationsPt extends Translations with BaseTranslations 'Lista de desejos'; @override String get following => 'A seguir'; @override String get plantares => 'Plantares'; + @override String get sales => 'Vendas'; @override String get settings => 'Definições'; } @@ -838,6 +840,31 @@ class _Translations$plantare$pt extends Translations$plantare$en { @override String get removeConfirm => 'Remover este compromisso?'; } +// Path: sale +class _Translations$sale$pt extends Translations$sale$en { + _Translations$sale$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get title => 'Vendas'; + @override String get help => 'Regista semente vendida ou comprada — dinheiro, Ğ1 ou qualquer moeda. Um modelo separado do presente e do Plantare. Nunca se cobra comissão pelas sementes.'; + @override String get add => 'Registar venda'; + @override String get empty => 'Ainda não há vendas. Anota aqui o que vendes ou compras.'; + @override String get iSold => 'Vendi'; + @override String get iBought => 'Comprei'; + @override String get direction => 'Vendes ou compras?'; + @override String get counterparty => 'Com quem?'; + @override String get counterpartyHint => 'Uma pessoa ou um coletivo (opcional)'; + @override String get amount => 'Montante'; + @override String get currency => 'Moeda'; + @override String get currencyHint => '€, Ğ1, horas… (opcional)'; + @override String get note => 'Nota (opcional)'; + @override String get save => 'Guardar'; + @override String get delete => 'Remover'; + @override String get removeConfirm => 'Remover esta venda?'; +} + // Path: intro.slides class _Translations$intro$slides$pt extends Translations$intro$slides$en { _Translations$intro$slides$pt._(TranslationsPt root) : this._root = root, super.internal(root); @@ -1207,6 +1234,7 @@ extension on TranslationsPt { 'menu.wishlist' => 'Lista de desejos', 'menu.following' => 'A seguir', 'menu.plantares' => 'Plantares', + 'menu.sales' => 'Vendas', 'menu.settings' => 'Definições', 'settings.language' => 'Idioma', 'settings.systemLanguage' => 'Idioma do sistema', @@ -1617,6 +1645,22 @@ extension on TranslationsPt { 'plantare.openSection' => 'Pendentes', 'plantare.settledSection' => 'Feitos', 'plantare.removeConfirm' => 'Remover este compromisso?', + 'sale.title' => 'Vendas', + 'sale.help' => 'Regista semente vendida ou comprada — dinheiro, Ğ1 ou qualquer moeda. Um modelo separado do presente e do Plantare. Nunca se cobra comissão pelas sementes.', + 'sale.add' => 'Registar venda', + 'sale.empty' => 'Ainda não há vendas. Anota aqui o que vendes ou compras.', + 'sale.iSold' => 'Vendi', + 'sale.iBought' => 'Comprei', + 'sale.direction' => 'Vendes ou compras?', + 'sale.counterparty' => 'Com quem?', + 'sale.counterpartyHint' => 'Uma pessoa ou um coletivo (opcional)', + 'sale.amount' => 'Montante', + 'sale.currency' => 'Moeda', + 'sale.currencyHint' => '€, Ğ1, horas… (opcional)', + 'sale.note' => 'Nota (opcional)', + 'sale.save' => 'Guardar', + 'sale.delete' => 'Remover', + 'sale.removeConfirm' => 'Remover esta venda?', _ => null, }; } diff --git a/apps/app_seeds/lib/ui/app_drawer.dart b/apps/app_seeds/lib/ui/app_drawer.dart index 0159156..9114992 100644 --- a/apps/app_seeds/lib/ui/app_drawer.dart +++ b/apps/app_seeds/lib/ui/app_drawer.dart @@ -44,6 +44,15 @@ class AppDrawer extends StatelessWidget { context.push('/plantares'); }, ), + // Local sales ledger — also offline. + _DrawerItem( + icon: const Icon(Icons.sell_outlined), + label: t.menu.sales, + onTap: () { + Navigator.of(context).pop(); + context.push('/sales'); + }, + ), _DrawerItem( icon: const Icon(Symbols.storefront), label: t.menu.market, diff --git a/apps/app_seeds/lib/ui/sale_sheet.dart b/apps/app_seeds/lib/ui/sale_sheet.dart new file mode 100644 index 0000000..0a18ba3 --- /dev/null +++ b/apps/app_seeds/lib/ui/sale_sheet.dart @@ -0,0 +1,165 @@ +import 'package:flutter/material.dart'; + +import '../data/variety_repository.dart'; +import '../db/enums.dart'; +import '../i18n/strings.g.dart'; +import 'theme.dart'; + +/// Opens the "record a sale" sheet. Optionally pre-attached to [varietyId] +/// (when opened from a variety's detail). +Future showSaleSheet( + BuildContext context, { + required VarietyRepository repository, + String? varietyId, +}) { + return showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (_) => _SaleSheet(repository: repository, varietyId: varietyId), + ); +} + +class _SaleSheet extends StatefulWidget { + const _SaleSheet({required this.repository, this.varietyId}); + + final VarietyRepository repository; + final String? varietyId; + + @override + State<_SaleSheet> createState() => _SaleSheetState(); +} + +class _SaleSheetState extends State<_SaleSheet> { + SaleDirection _direction = SaleDirection.iSold; + final _counterparty = TextEditingController(); + final _amount = TextEditingController(); + final _currency = TextEditingController(); + final _note = TextEditingController(); + bool _saving = false; + + @override + void dispose() { + _counterparty.dispose(); + _amount.dispose(); + _currency.dispose(); + _note.dispose(); + super.dispose(); + } + + String? _nullIfBlank(String s) => s.trim().isEmpty ? null : s.trim(); + + Future _save() async { + setState(() => _saving = true); + await widget.repository.createSale( + direction: _direction, + varietyId: widget.varietyId, + counterparty: _nullIfBlank(_counterparty.text), + amount: double.tryParse(_amount.text.trim().replaceAll(',', '.')), + currency: _nullIfBlank(_currency.text), + note: _nullIfBlank(_note.text), + ); + if (mounted) Navigator.of(context).pop(); + } + + @override + Widget build(BuildContext context) { + final t = context.t; + return Padding( + padding: EdgeInsets.only( + left: 16, + right: 16, + top: 16, + bottom: MediaQuery.of(context).viewInsets.bottom + 16, + ), + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text(t.sale.add, style: Theme.of(context).textTheme.titleLarge), + const SizedBox(height: 4), + Text(t.sale.help, + style: const TextStyle(color: seedMuted, fontSize: 13)), + const SizedBox(height: 16), + Text(t.sale.direction, + style: Theme.of(context).textTheme.labelLarge), + const SizedBox(height: 6), + for (final d in SaleDirection.values) + ListTile( + key: Key('sale.direction.${d.name}'), + contentPadding: EdgeInsets.zero, + leading: Icon( + _direction == d + ? Icons.radio_button_checked + : Icons.radio_button_unchecked, + color: _direction == d ? seedGreen : seedMuted, + ), + title: Text( + d == SaleDirection.iSold ? t.sale.iSold : t.sale.iBought), + onTap: () => setState(() => _direction = d), + ), + const SizedBox(height: 8), + TextField( + key: const Key('sale.counterparty'), + controller: _counterparty, + textCapitalization: TextCapitalization.words, + decoration: InputDecoration( + labelText: t.sale.counterparty, + helperText: t.sale.counterpartyHint, + border: const OutlineInputBorder(), + ), + ), + const SizedBox(height: 12), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: TextField( + key: const Key('sale.amount'), + controller: _amount, + keyboardType: const TextInputType.numberWithOptions( + decimal: true), + decoration: InputDecoration( + labelText: t.sale.amount, + border: const OutlineInputBorder(), + ), + ), + ), + const SizedBox(width: 12), + Expanded( + child: TextField( + key: const Key('sale.currency'), + controller: _currency, + decoration: InputDecoration( + labelText: t.sale.currency, + helperText: t.sale.currencyHint, + helperMaxLines: 2, + border: const OutlineInputBorder(), + ), + ), + ), + ], + ), + const SizedBox(height: 12), + TextField( + key: const Key('sale.note'), + controller: _note, + minLines: 1, + maxLines: 3, + decoration: InputDecoration( + labelText: t.sale.note, + border: const OutlineInputBorder(), + ), + ), + const SizedBox(height: 20), + FilledButton( + key: const Key('sale.save'), + onPressed: _saving ? null : _save, + child: Text(t.sale.save), + ), + ], + ), + ), + ); + } +} diff --git a/apps/app_seeds/lib/ui/sales_screen.dart b/apps/app_seeds/lib/ui/sales_screen.dart new file mode 100644 index 0000000..957bc89 --- /dev/null +++ b/apps/app_seeds/lib/ui/sales_screen.dart @@ -0,0 +1,111 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../data/variety_repository.dart'; +import '../db/database.dart'; +import '../db/enums.dart'; +import '../i18n/strings.g.dart'; +import 'sale_sheet.dart'; +import 'theme.dart'; + +/// The Sales screen — a local ledger of seed sold or bought, in any currency. +/// A model separate from a gift or a Plantare. Reads the encrypted inventory DB. +class SalesScreen extends StatelessWidget { + const SalesScreen({super.key}); + + @override + Widget build(BuildContext context) { + final t = context.t; + final repo = context.read(); + return Scaffold( + appBar: AppBar(title: Text(t.sale.title)), + floatingActionButton: FloatingActionButton.extended( + key: const Key('sales.add'), + onPressed: () => showSaleSheet(context, repository: repo), + icon: const Icon(Icons.add), + label: Text(t.sale.add), + ), + body: StreamBuilder>( + stream: repo.watchSales(), + builder: (context, snapshot) { + final sales = snapshot.data; + if (sales == null) { + return const Center(child: CircularProgressIndicator()); + } + if (sales.isEmpty) { + return Center( + child: Padding( + padding: const EdgeInsets.all(32), + child: Text( + t.sale.empty, + textAlign: TextAlign.center, + style: const TextStyle(color: seedMuted, fontSize: 15), + ), + ), + ); + } + return ListView.separated( + padding: const EdgeInsets.only(bottom: 88), + itemCount: sales.length, + separatorBuilder: (_, _) => const Divider(height: 1), + itemBuilder: (context, i) => _SaleTile(sales[i], repo), + ); + }, + ), + ); + } +} + +class _SaleTile extends StatelessWidget { + const _SaleTile(this.s, this.repo); + + final Sale s; + final VarietyRepository repo; + + String _money() { + final amount = s.amount; + if (amount == null) return s.currency?.trim() ?? ''; + // Drop a trailing .0 so "5.0 €" reads "5 €". + final n = amount == amount.roundToDouble() + ? amount.toInt().toString() + : amount.toString(); + return [n, s.currency?.trim()].where((e) => e != null && e.isNotEmpty).join(' '); + } + + @override + Widget build(BuildContext context) { + final t = context.t; + final iSold = s.direction == SaleDirection.iSold; + final money = _money(); + final date = MaterialLocalizations.of(context) + .formatShortDate(DateTime.fromMillisecondsSinceEpoch(s.soldOn)); + final subtitle = [ + iSold ? t.sale.iSold : t.sale.iBought, + if (s.counterparty?.trim().isNotEmpty ?? false) s.counterparty!.trim(), + date, + ].join(' · '); + return ListTile( + leading: Icon( + iSold ? Icons.sell_outlined : Icons.shopping_bag_outlined, + color: seedGreen, + ), + title: Text( + money.isEmpty + ? (s.note?.trim().isNotEmpty ?? false + ? s.note!.trim() + : (iSold ? t.sale.iSold : t.sale.iBought)) + : money, + style: const TextStyle(fontWeight: FontWeight.w600), + ), + subtitle: Text(subtitle, maxLines: 2, overflow: TextOverflow.ellipsis), + trailing: PopupMenuButton( + key: Key('sale.menu.${s.id}'), + onSelected: (v) { + if (v == 'delete') repo.deleteSale(s.id); + }, + itemBuilder: (context) => + [PopupMenuItem(value: 'delete', child: Text(t.sale.delete))], + ), + ); + } +} diff --git a/apps/app_seeds/lib/ui/variety_detail_screen.dart b/apps/app_seeds/lib/ui/variety_detail_screen.dart index efae7f7..3edc414 100644 --- a/apps/app_seeds/lib/ui/variety_detail_screen.dart +++ b/apps/app_seeds/lib/ui/variety_detail_screen.dart @@ -18,6 +18,7 @@ import 'harvest_date_picker.dart'; import 'photo_pick.dart'; import 'plantare_sheet.dart'; import 'quantity_kind_l10n.dart'; +import 'sale_sheet.dart'; import 'quantity_picker.dart'; import 'seed_glyph.dart'; import 'theme.dart'; @@ -110,19 +111,31 @@ class _DetailView extends StatelessWidget { ], ), const SizedBox(height: 16), - _SectionTitle(t.plantare.title), - Align( - alignment: AlignmentDirectional.centerStart, - child: OutlinedButton.icon( - key: const Key('detail.addPlantare'), - icon: const Icon(Icons.volunteer_activism_outlined, size: 18), - onPressed: () => showPlantareSheet( - context, - repository: context.read(), - varietyId: detail.id, + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + OutlinedButton.icon( + key: const Key('detail.addPlantare'), + icon: const Icon(Icons.volunteer_activism_outlined, size: 18), + onPressed: () => showPlantareSheet( + context, + repository: context.read(), + varietyId: detail.id, + ), + label: Text(t.plantare.add), ), - label: Text(t.plantare.add), - ), + OutlinedButton.icon( + key: const Key('detail.addSale'), + icon: const Icon(Icons.sell_outlined, size: 18), + onPressed: () => showSaleSheet( + context, + repository: context.read(), + varietyId: detail.id, + ), + label: Text(t.sale.add), + ), + ], ), if (detail.notes != null && detail.notes!.trim().isNotEmpty) ...[ const SizedBox(height: 16), diff --git a/apps/app_seeds/test/data/sales_test.dart b/apps/app_seeds/test/data/sales_test.dart new file mode 100644 index 0000000..4c66dc0 --- /dev/null +++ b/apps/app_seeds/test/data/sales_test.dart @@ -0,0 +1,71 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:tane/db/database.dart'; +import 'package:tane/db/enums.dart'; + +import '../support/test_support.dart'; + +/// A Sale is a recorded seed sale/purchase — a model separate from a gift or a +/// Plantare, with a price in any currency. +void main() { + late AppDatabase db; + setUp(() => db = newTestDatabase()); + tearDown(() => db.close()); + + test('records a sale with amount + currency and lists it', () async { + final repo = newTestRepository(db); + final vid = await repo.addQuickVariety(label: 'Tomate rosa'); + await repo.createSale( + direction: SaleDirection.iSold, + varietyId: vid, + counterparty: 'Ana', + amount: 5, + currency: '€', + ); + + final all = await repo.watchSales().first; + expect(all.single.direction, SaleDirection.iSold); + expect(all.single.amount, 5); + expect(all.single.currency, '€'); + expect(all.single.counterparty, 'Ana'); + expect(await repo.watchSalesForVariety(vid).first, hasLength(1)); + }); + + test('supports any currency (Ğ1, time…) and a price-less record', () async { + final repo = newTestRepository(db); + await repo.createSale(direction: SaleDirection.iBought, amount: 12, currency: 'Ğ1'); + await repo.createSale(direction: SaleDirection.iSold); // no figure yet + final all = await repo.watchSales().first; + expect(all, hasLength(2)); + expect(all.any((s) => s.currency == 'Ğ1' && s.amount == 12), isTrue); + expect(all.any((s) => s.amount == null), isTrue); + }); + + test('deleting a sale tombstones it', () async { + final repo = newTestRepository(db); + final id = await repo.createSale(direction: SaleDirection.iSold, amount: 3); + expect(await repo.watchSales().first, hasLength(1)); + await repo.deleteSale(id); + expect(await repo.watchSales().first, isEmpty); + }); + + test('sales survive a backup round-trip', () async { + final repoA = newTestRepository(db); + await repoA.createSale( + direction: SaleDirection.iSold, + counterparty: 'Feria de la comarca', + amount: 2.5, + currency: '€', + ); + final snapshot = await repoA.exportInventory(); + expect(snapshot.sales, hasLength(1)); + + final dbB = newTestDatabase(); + addTearDown(dbB.close); + final repoB = newTestRepository(dbB); + await repoB.importInventory(snapshot); + final onB = await repoB.watchSales().first; + expect(onB.single.amount, 2.5); + expect(onB.single.currency, '€'); + expect(onB.single.counterparty, 'Feria de la comarca'); + }); +} diff --git a/apps/app_seeds/test/db/migration_test.dart b/apps/app_seeds/test/db/migration_test.dart index 4181ecf..a5c6676 100644 --- a/apps/app_seeds/test/db/migration_test.dart +++ b/apps/app_seeds/test/db/migration_test.dart @@ -11,19 +11,19 @@ void main() { verifier = SchemaVerifier(GeneratedHelper()); }); - test('freshly created database matches the exported schema v9', () async { - final schema = await verifier.schemaAt(9); + test('freshly created database matches the exported schema v10', () async { + final schema = await verifier.schemaAt(10); final db = AppDatabase(schema.newConnection()); - await verifier.migrateAndValidate(db, 9); + await verifier.migrateAndValidate(db, 10); await db.close(); }); - // Every historical version upgrades cleanly to the current schema (v9). - for (var from = 1; from <= 8; from++) { - test('upgrades v$from → v9 and matches the fresh schema', () async { + // Every historical version upgrades cleanly to the current schema (v10). + for (var from = 1; from <= 9; from++) { + test('upgrades v$from → v10 and matches the fresh schema', () async { final connection = await verifier.startAt(from); final db = AppDatabase(connection); - await verifier.migrateAndValidate(db, 9); + await verifier.migrateAndValidate(db, 10); await db.close(); }); } diff --git a/apps/app_seeds/test/db/schema/schema.dart b/apps/app_seeds/test/db/schema/schema.dart index 3f1b776..e3e260c 100644 --- a/apps/app_seeds/test/db/schema/schema.dart +++ b/apps/app_seeds/test/db/schema/schema.dart @@ -13,6 +13,7 @@ import 'schema_v6.dart' as v6; import 'schema_v7.dart' as v7; import 'schema_v8.dart' as v8; import 'schema_v9.dart' as v9; +import 'schema_v10.dart' as v10; class GeneratedHelper implements SchemaInstantiationHelper { @override @@ -36,10 +37,12 @@ class GeneratedHelper implements SchemaInstantiationHelper { return v8.DatabaseAtV8(db); case 9: return v9.DatabaseAtV9(db); + case 10: + return v10.DatabaseAtV10(db); default: throw MissingSchemaException(version, versions); } } - static const versions = const [1, 2, 3, 4, 5, 6, 7, 8, 9]; + static const versions = const [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; } diff --git a/apps/app_seeds/test/db/schema/schema_v10.dart b/apps/app_seeds/test/db/schema/schema_v10.dart new file mode 100644 index 0000000..cb9ba19 --- /dev/null +++ b/apps/app_seeds/test/db/schema/schema_v10.dart @@ -0,0 +1,1997 @@ +// dart format width=80 +import 'dart:typed_data' as i2; +// GENERATED BY drift_dev, DO NOT MODIFY. +// ignore_for_file: type=lint,unused_import +// +import 'package:drift/drift.dart'; + +class Varieties extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Varieties(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn label = GeneratedColumn( + 'label', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn speciesId = GeneratedColumn( + 'species_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn cultivarName = GeneratedColumn( + 'cultivar_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn category = GeneratedColumn( + 'category', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn notes = GeneratedColumn( + 'notes', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn isDraft = GeneratedColumn( + 'is_draft', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_draft IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn isOrganic = GeneratedColumn( + 'is_organic', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_organic IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn needsReproduction = GeneratedColumn( + 'needs_reproduction', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: + 'NOT NULL DEFAULT 0 CHECK (needs_reproduction IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn sowMonths = GeneratedColumn( + 'sow_months', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn transplantMonths = GeneratedColumn( + 'transplant_months', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn floweringMonths = GeneratedColumn( + 'flowering_months', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn fruitingMonths = GeneratedColumn( + 'fruiting_months', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn seedHarvestMonths = GeneratedColumn( + 'seed_harvest_months', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + label, + speciesId, + cultivarName, + category, + notes, + isDraft, + isOrganic, + needsReproduction, + sowMonths, + transplantMonths, + floweringMonths, + fruitingMonths, + seedHarvestMonths, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'varieties'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + Varieties createAlias(String alias) { + return Varieties(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class VarietyVernacularNames extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + VarietyVernacularNames(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn varietyId = GeneratedColumn( + 'variety_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn language = GeneratedColumn( + 'language', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn region = GeneratedColumn( + 'region', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + varietyId, + name, + language, + region, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'variety_vernacular_names'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + VarietyVernacularNames createAlias(String alias) { + return VarietyVernacularNames(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class Species extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Species(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn scientificName = GeneratedColumn( + 'scientific_name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn wikidataQid = GeneratedColumn( + 'wikidata_qid', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn gbifKey = GeneratedColumn( + 'gbif_key', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn family = GeneratedColumn( + 'family', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn isBundled = GeneratedColumn( + 'is_bundled', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_bundled IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn viabilityYears = GeneratedColumn( + 'viability_years', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + scientificName, + wikidataQid, + gbifKey, + family, + isBundled, + viabilityYears, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'species'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + Species createAlias(String alias) { + return Species(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class SpeciesCommonNames extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + SpeciesCommonNames(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn speciesId = GeneratedColumn( + 'species_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn language = GeneratedColumn( + 'language', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + speciesId, + name, + language, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'species_common_names'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + SpeciesCommonNames createAlias(String alias) { + return SpeciesCommonNames(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class Lots extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Lots(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn varietyId = GeneratedColumn( + 'variety_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT \'seed\'', + defaultValue: const CustomExpression('\'seed\''), + ); + late final GeneratedColumn harvestYear = GeneratedColumn( + 'harvest_year', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn harvestMonth = GeneratedColumn( + 'harvest_month', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn quantityKind = GeneratedColumn( + 'quantity_kind', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn quantityPrecise = GeneratedColumn( + 'quantity_precise', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn quantityLabel = GeneratedColumn( + 'quantity_label', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn presentation = GeneratedColumn( + 'presentation', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn storageLocation = GeneratedColumn( + 'storage_location', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn offerStatus = GeneratedColumn( + 'offer_status', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT \'private\'', + defaultValue: const CustomExpression('\'private\''), + ); + late final GeneratedColumn seedbankId = GeneratedColumn( + 'seedbank_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn originName = GeneratedColumn( + 'origin_name', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn originPlace = GeneratedColumn( + 'origin_place', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn abundance = GeneratedColumn( + 'abundance', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn preservationFormat = + GeneratedColumn( + 'preservation_format', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + varietyId, + type, + harvestYear, + harvestMonth, + quantityKind, + quantityPrecise, + quantityLabel, + presentation, + storageLocation, + offerStatus, + seedbankId, + originName, + originPlace, + abundance, + preservationFormat, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'lots'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + Lots createAlias(String alias) { + return Lots(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class GerminationTests extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + GerminationTests(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn lotId = GeneratedColumn( + 'lot_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn testedOn = GeneratedColumn( + 'tested_on', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn sampleSize = GeneratedColumn( + 'sample_size', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn germinatedCount = GeneratedColumn( + 'germinated_count', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn notes = GeneratedColumn( + 'notes', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + lotId, + testedOn, + sampleSize, + germinatedCount, + notes, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'germination_tests'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + GerminationTests createAlias(String alias) { + return GerminationTests(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class ConditionChecks extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + ConditionChecks(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn lotId = GeneratedColumn( + 'lot_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn checkedOn = GeneratedColumn( + 'checked_on', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn containerCount = GeneratedColumn( + 'container_count', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn desiccantState = GeneratedColumn( + 'desiccant_state', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn notes = GeneratedColumn( + 'notes', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + lotId, + checkedOn, + containerCount, + desiccantState, + notes, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'condition_checks'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + ConditionChecks createAlias(String alias) { + return ConditionChecks(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class Movements extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Movements(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn lotId = GeneratedColumn( + 'lot_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn occurredOn = GeneratedColumn( + 'occurred_on', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn counterpartyId = GeneratedColumn( + 'counterparty_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn quantityKind = GeneratedColumn( + 'quantity_kind', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn quantityPrecise = GeneratedColumn( + 'quantity_precise', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn quantityLabel = GeneratedColumn( + 'quantity_label', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn parentMovementId = GeneratedColumn( + 'parent_movement_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn plantareId = GeneratedColumn( + 'plantare_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn notes = GeneratedColumn( + 'notes', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + lastAuthor, + schemaRowVersion, + lotId, + type, + occurredOn, + counterpartyId, + quantityKind, + quantityPrecise, + quantityLabel, + parentMovementId, + plantareId, + notes, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'movements'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + Movements createAlias(String alias) { + return Movements(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class Parties extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Parties(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn displayName = GeneratedColumn( + 'display_name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn publicKey = GeneratedColumn( + 'public_key', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn kind = GeneratedColumn( + 'kind', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT \'person\'', + defaultValue: const CustomExpression('\'person\''), + ); + late final GeneratedColumn note = GeneratedColumn( + 'note', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + displayName, + publicKey, + kind, + note, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'parties'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + Parties createAlias(String alias) { + return Parties(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class Attachments extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Attachments(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn parentType = GeneratedColumn( + 'parent_type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn parentId = GeneratedColumn( + 'parent_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn kind = GeneratedColumn( + 'kind', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn uri = GeneratedColumn( + 'uri', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn bytes = + GeneratedColumn( + 'bytes', + aliasedName, + true, + type: DriftSqlType.blob, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn mimeType = GeneratedColumn( + 'mime_type', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn sortOrder = GeneratedColumn( + 'sort_order', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0', + defaultValue: const CustomExpression('0'), + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + parentType, + parentId, + kind, + uri, + bytes, + mimeType, + sortOrder, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'attachments'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + Attachments createAlias(String alias) { + return Attachments(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class ExternalLinks extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + ExternalLinks(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn parentType = GeneratedColumn( + 'parent_type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn parentId = GeneratedColumn( + 'parent_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn url = GeneratedColumn( + 'url', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn title = GeneratedColumn( + 'title', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + parentType, + parentId, + url, + title, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'external_links'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + ExternalLinks createAlias(String alias) { + return ExternalLinks(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class Plantares extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Plantares(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn varietyId = GeneratedColumn( + 'variety_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn direction = GeneratedColumn( + 'direction', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn counterparty = GeneratedColumn( + 'counterparty', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn owedDescription = GeneratedColumn( + 'owed_description', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn madeOn = GeneratedColumn( + 'made_on', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn dueBy = GeneratedColumn( + 'due_by', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn status = GeneratedColumn( + 'status', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT \'open\'', + defaultValue: const CustomExpression('\'open\''), + ); + late final GeneratedColumn settledOn = GeneratedColumn( + 'settled_on', + aliasedName, + true, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn note = GeneratedColumn( + 'note', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + varietyId, + direction, + counterparty, + owedDescription, + madeOn, + dueBy, + status, + settledOn, + note, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'plantares'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + Plantares createAlias(String alias) { + return Plantares(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class Sales extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Sales(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn lastAuthor = GeneratedColumn( + 'last_author', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn isDeleted = GeneratedColumn( + 'is_deleted', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 0 CHECK (is_deleted IN (0, 1))', + defaultValue: const CustomExpression('0'), + ); + late final GeneratedColumn schemaRowVersion = GeneratedColumn( + 'schema_row_version', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL DEFAULT 1', + defaultValue: const CustomExpression('1'), + ); + late final GeneratedColumn varietyId = GeneratedColumn( + 'variety_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn direction = GeneratedColumn( + 'direction', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn counterparty = GeneratedColumn( + 'counterparty', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn amount = GeneratedColumn( + 'amount', + aliasedName, + true, + type: DriftSqlType.double, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn currency = GeneratedColumn( + 'currency', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + late final GeneratedColumn soldOn = GeneratedColumn( + 'sold_on', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + $customConstraints: 'NOT NULL', + ); + late final GeneratedColumn note = GeneratedColumn( + 'note', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: 'NULL', + ); + @override + List get $columns => [ + id, + createdAt, + updatedAt, + lastAuthor, + isDeleted, + schemaRowVersion, + varietyId, + direction, + counterparty, + amount, + currency, + soldOn, + note, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'sales'; + @override + Set get $primaryKey => {id}; + @override + Never map(Map data, {String? tablePrefix}) { + throw UnsupportedError('TableInfo.map in schema verification code'); + } + + @override + Sales createAlias(String alias) { + return Sales(attachedDatabase, alias); + } + + @override + List get customConstraints => const ['PRIMARY KEY(id)']; + @override + bool get dontWriteConstraints => true; +} + +class DatabaseAtV10 extends GeneratedDatabase { + DatabaseAtV10(QueryExecutor e) : super(e); + late final Varieties varieties = Varieties(this); + late final VarietyVernacularNames varietyVernacularNames = + VarietyVernacularNames(this); + late final Species species = Species(this); + late final SpeciesCommonNames speciesCommonNames = SpeciesCommonNames(this); + late final Lots lots = Lots(this); + late final GerminationTests germinationTests = GerminationTests(this); + late final ConditionChecks conditionChecks = ConditionChecks(this); + late final Movements movements = Movements(this); + late final Parties parties = Parties(this); + late final Attachments attachments = Attachments(this); + late final ExternalLinks externalLinks = ExternalLinks(this); + late final Plantares plantares = Plantares(this); + late final Sales sales = Sales(this); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [ + varieties, + varietyVernacularNames, + species, + speciesCommonNames, + lots, + germinationTests, + conditionChecks, + movements, + parties, + attachments, + externalLinks, + plantares, + sales, + ]; + @override + int get schemaVersion => 10; +} diff --git a/apps/app_seeds/test/ui/small_screen_overflow_test.dart b/apps/app_seeds/test/ui/small_screen_overflow_test.dart index 4e9faf3..f3b0dd6 100644 --- a/apps/app_seeds/test/ui/small_screen_overflow_test.dart +++ b/apps/app_seeds/test/ui/small_screen_overflow_test.dart @@ -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