Add full app source
Adds the Flutter inventory app source, cleaned up for a shared repo: generic package name, no hardcoded ERP endpoints (moved to gitignored local config), no dead auth code, no debug logging of session data.
This commit is contained in:
110
lib/models/depot.dart
Normal file
110
lib/models/depot.dart
Normal file
@@ -0,0 +1,110 @@
|
||||
import 'package:inventory_app/utils.dart';
|
||||
|
||||
class Depot {
|
||||
int? id;
|
||||
String? name;
|
||||
MetaFile? picture;
|
||||
|
||||
Depot({this.id, this.name, this.picture});
|
||||
|
||||
Depot.fromJson(Map<dynamic, dynamic> json) {
|
||||
id = json['id'];
|
||||
name = json['name'];
|
||||
picture =
|
||||
json['picture'] != null ? MetaFile.fromJson(json['picture']) : null;
|
||||
}
|
||||
|
||||
Map<dynamic, dynamic> toJson() {
|
||||
final Map<dynamic, dynamic> data = {};
|
||||
data['id'] = this.id;
|
||||
data['name'] = this.name;
|
||||
if (picture != null) {
|
||||
data['picture'] = picture!.toJson();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/// 👇 Get full image URL (you can customize baseUrl to be from `AxelorClient.baseUrl`)
|
||||
String? get imageUrl {
|
||||
if (picture?.id != null) {
|
||||
return '${Utils.url}/ws/rest/com.axelor.meta.db.MetaFile/${picture!.id}/content/download';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is Depot && runtimeType == other.runtimeType && id == other.id;
|
||||
|
||||
@override
|
||||
int get hashCode => id.hashCode;
|
||||
}
|
||||
|
||||
class Company {
|
||||
String? code;
|
||||
String? name;
|
||||
int? id;
|
||||
int? version;
|
||||
|
||||
Company({this.code, this.name, this.id, this.version});
|
||||
|
||||
Company.fromJson(Map<String, dynamic> json) {
|
||||
code = json['code'];
|
||||
name = json['name'];
|
||||
id = json['id'];
|
||||
version = json['$version'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['code'] = this.code;
|
||||
data['name'] = this.name;
|
||||
data['id'] = this.id;
|
||||
data['$version'] = this.version;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class UpdatedBy {
|
||||
String? code;
|
||||
String? fullName;
|
||||
int? id;
|
||||
int? version;
|
||||
|
||||
UpdatedBy({this.code, this.fullName, this.id, this.version});
|
||||
|
||||
UpdatedBy.fromJson(Map<String, dynamic> json) {
|
||||
code = json['code'];
|
||||
fullName = json['fullName'];
|
||||
id = json['id'];
|
||||
version = json['$version'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['code'] = this.code;
|
||||
data['fullName'] = this.fullName;
|
||||
data['id'] = this.id;
|
||||
data['$version'] = this.version;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class MetaFile {
|
||||
String? fileName;
|
||||
int? id;
|
||||
int? version;
|
||||
|
||||
MetaFile({this.fileName, this.id, this.version});
|
||||
|
||||
MetaFile.fromJson(Map<String, dynamic> json) {
|
||||
fileName = json['fileName'];
|
||||
id = json['id'];
|
||||
version = json['$version'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {'fileName': fileName, 'id': id, '\$version': version};
|
||||
}
|
||||
}
|
||||
31
lib/models/famille_produit.dart
Normal file
31
lib/models/famille_produit.dart
Normal file
@@ -0,0 +1,31 @@
|
||||
class FamilleProduit {
|
||||
int? id;
|
||||
String? name;
|
||||
|
||||
FamilleProduit({this.id, this.name});
|
||||
|
||||
FamilleProduit.fromJson(Map<dynamic, dynamic> json) {
|
||||
id = json['id'];
|
||||
name = json['name'];
|
||||
}
|
||||
|
||||
Map<dynamic, dynamic> toJson() {
|
||||
final Map<dynamic, dynamic> data = {};
|
||||
data['id'] = id;
|
||||
data['name'] = name;
|
||||
return data;
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is FamilleProduit &&
|
||||
runtimeType == other.runtimeType &&
|
||||
id == other.id;
|
||||
|
||||
@override
|
||||
String toString() => name ?? 'Unknown';
|
||||
|
||||
@override
|
||||
int get hashCode => id.hashCode;
|
||||
}
|
||||
142
lib/models/inventory_line.dart
Normal file
142
lib/models/inventory_line.dart
Normal file
@@ -0,0 +1,142 @@
|
||||
import 'package:inventory_app/models/product.dart';
|
||||
|
||||
class InventoryLine {
|
||||
int? id;
|
||||
int? version;
|
||||
final int inventoryId;
|
||||
final int productId;
|
||||
final String productName;
|
||||
final double currentQty;
|
||||
final double realQty;
|
||||
final int unitId;
|
||||
final String? description;
|
||||
final String? observation;
|
||||
final String ticketId;
|
||||
final String? rack;
|
||||
final int? trackingNumberId;
|
||||
final int countingTypeSelect;
|
||||
final int stockLocationId;
|
||||
double? firstCounting;
|
||||
double? secondCounting;
|
||||
double? thirdCounting;
|
||||
String? firstCountingDate;
|
||||
String? secondCountingDate;
|
||||
String? thirdCountingDate;
|
||||
Map<String, dynamic>? firstCountingByUser;
|
||||
Map<String, dynamic>? secondCountingByUser;
|
||||
Map<String, dynamic>? thirdCountingByUser;
|
||||
Product? product;
|
||||
|
||||
InventoryLine({
|
||||
this.id,
|
||||
this.version,
|
||||
required this.inventoryId,
|
||||
required this.productId,
|
||||
required this.productName,
|
||||
required this.currentQty,
|
||||
required this.realQty,
|
||||
required this.unitId,
|
||||
this.description,
|
||||
this.observation,
|
||||
required this.ticketId,
|
||||
this.rack,
|
||||
this.trackingNumberId,
|
||||
required this.countingTypeSelect,
|
||||
required this.stockLocationId,
|
||||
required this.firstCounting,
|
||||
required this.secondCounting,
|
||||
required this.thirdCounting,
|
||||
this.firstCountingDate,
|
||||
this.secondCountingDate,
|
||||
this.thirdCountingDate,
|
||||
this.firstCountingByUser,
|
||||
this.secondCountingByUser,
|
||||
this.thirdCountingByUser,
|
||||
this.product
|
||||
});
|
||||
|
||||
factory InventoryLine.fromJson(Map<String, dynamic> json) {
|
||||
double parseDouble(dynamic value) {
|
||||
if (value == null) return 0.0;
|
||||
if (value is num) return value.toDouble();
|
||||
if (value is String) return double.tryParse(value) ?? 0.0;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return InventoryLine(
|
||||
id: json['id'],
|
||||
version: json['version'],
|
||||
inventoryId: json['inventory']?['id'] ?? 0,
|
||||
productId: json['product']?['id'] ?? 0,
|
||||
productName: json['productName'] ?? '',
|
||||
currentQty: parseDouble(json['currentQty']),
|
||||
realQty: parseDouble(json['realQty']),
|
||||
unitId: json['unit']?['id'] ?? 0,
|
||||
description: json['description'],
|
||||
observation: json['observation'],
|
||||
ticketId: json['ticketId'] ?? '',
|
||||
rack: json['rack'],
|
||||
trackingNumberId: json['trackingNumber']?['id'],
|
||||
countingTypeSelect: json['countingTypeSelect'] ?? 0,
|
||||
stockLocationId: json['stockLocation']?['id'] ?? 0,
|
||||
firstCounting: parseDouble(json['firstCounting']),
|
||||
secondCounting: parseDouble(json['secondCounting']),
|
||||
thirdCounting: parseDouble(json['thirdCounting']),
|
||||
firstCountingDate: json['firstCountingDate'],
|
||||
secondCountingDate: json['secondCountingDate'],
|
||||
thirdCountingDate: json['thirdCountingDate'],
|
||||
firstCountingByUser: json['firstCountingByUser'] != null
|
||||
? Map<String, dynamic>.from(json['firstCountingByUser'])
|
||||
: null,
|
||||
secondCountingByUser: json['secondCountingByUser'] != null
|
||||
? Map<String, dynamic>.from(json['secondCountingByUser'])
|
||||
: null,
|
||||
thirdCountingByUser: json['thirdCountingByUser'] != null
|
||||
? Map<String, dynamic>.from(json['thirdCountingByUser'])
|
||||
: null,
|
||||
product: json['product'] != null ? Product.fromJson(json['product']) : null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> map = {
|
||||
if (id != null) "id": id,
|
||||
if (version != null) "version": version,
|
||||
"inventory": {"id": inventoryId},
|
||||
"product": {"id": productId},
|
||||
"productName": productName,
|
||||
"currentQty": currentQty,
|
||||
"realQty": realQty,
|
||||
"unit": {"id": unitId},
|
||||
"description": description,
|
||||
"observation": observation,
|
||||
"ticketId": ticketId,
|
||||
"rack": rack,
|
||||
if (trackingNumberId != null) "trackingNumber": {"id": trackingNumberId},
|
||||
"countingTypeSelect": countingTypeSelect,
|
||||
"stockLocation": {"id": stockLocationId},
|
||||
"firstCounting": firstCounting,
|
||||
"secondCounting": secondCounting,
|
||||
"thirdCounting": thirdCounting,
|
||||
};
|
||||
|
||||
if (firstCountingDate != null) map['firstCountingDate'] = firstCountingDate;
|
||||
if (secondCountingDate != null)
|
||||
map['secondCountingDate'] = secondCountingDate;
|
||||
if (thirdCountingDate != null) map['thirdCountingDate'] = thirdCountingDate;
|
||||
if (firstCountingByUser != null)
|
||||
map['firstCountingByUser'] = firstCountingByUser;
|
||||
if (secondCountingByUser != null)
|
||||
map['secondCountingByUser'] = secondCountingByUser;
|
||||
if (thirdCountingByUser != null)
|
||||
map['thirdCountingByUser'] = thirdCountingByUser;
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'InventoryLine{id: $id, version: $version, inventoryId: $inventoryId, productId: $productId, productName: $productName, currentQty: $currentQty, realQty: $realQty, unitId: $unitId, description: $description, observation: $observation, ticketId: $ticketId, rack: $rack, trackingNumberId: $trackingNumberId, countingTypeSelect: $countingTypeSelect, stockLocationId: $stockLocationId, firstCounting: $firstCounting, secondCounting: $secondCounting, thirdCounting: $thirdCounting, firstCountingDate: $firstCountingDate, secondCountingDate: $secondCountingDate, thirdCountingDate: $thirdCountingDate, firstCountingByUser: $firstCountingByUser, secondCountingByUser: $secondCountingByUser, thirdCountingByUser: $thirdCountingByUser}';
|
||||
}
|
||||
}
|
||||
139
lib/models/product.dart
Normal file
139
lib/models/product.dart
Normal file
@@ -0,0 +1,139 @@
|
||||
import 'package:inventory_app/utils.dart';
|
||||
|
||||
class Product {
|
||||
Unit? unit;
|
||||
Unit? purchaseUnit;
|
||||
String? code;
|
||||
String? name;
|
||||
int? id;
|
||||
int? version;
|
||||
String? productTypeSelect; // must be int, not String
|
||||
int? familleProduit; // will be sent as object {id: X}
|
||||
int? sousFamilleProduit; // same
|
||||
String? internalDescription; // custom logic (not Axelor default field)
|
||||
String? serialNumber;
|
||||
String? description;
|
||||
MetaFile? picture;
|
||||
String? procurementMethodSelect = 'buy';
|
||||
|
||||
Product({
|
||||
this.unit,
|
||||
this.purchaseUnit,
|
||||
this.code,
|
||||
this.name,
|
||||
this.id,
|
||||
this.version,
|
||||
this.productTypeSelect, // use 0,1,2
|
||||
this.familleProduit,
|
||||
this.sousFamilleProduit,
|
||||
this.internalDescription,
|
||||
this.serialNumber,
|
||||
this.description,
|
||||
this.picture,
|
||||
this.procurementMethodSelect,
|
||||
});
|
||||
|
||||
Product.fromJson(Map<String, dynamic> json) {
|
||||
unit = json['unit'] != null ? Unit.fromJson(json['unit']) : null;
|
||||
purchaseUnit =
|
||||
json['purchaseUnit'] != null
|
||||
? Unit.fromJson(json['purchaseUnit'])
|
||||
: null;
|
||||
code = json['code'];
|
||||
name = json['name'];
|
||||
id = json['id'];
|
||||
version = json['version'];
|
||||
productTypeSelect = json['productTypeSelect'];
|
||||
familleProduit = json['familleProduit']?['id']; // Axelor wraps it in object
|
||||
sousFamilleProduit = json['sousFamilleProduit']?['id'];
|
||||
internalDescription = json['internalDescription'];
|
||||
serialNumber = json['serialNumber'];
|
||||
description = json['description'];
|
||||
picture =
|
||||
json['picture'] != null ? MetaFile.fromJson(json['picture']) : null;
|
||||
procurementMethodSelect = json['procurementMethodSelect'] ?? 'buy';
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = {};
|
||||
|
||||
if (unit != null) {
|
||||
data['unit'] = unit!.toJson();
|
||||
}
|
||||
if (purchaseUnit != null) {
|
||||
data['purchaseUnit'] = purchaseUnit!.toJson();
|
||||
}
|
||||
if (code != null) data['code'] = code;
|
||||
if (name != null) data['name'] = name;
|
||||
if (id != null) data['id'] = id;
|
||||
if (version != null) data['version'] = version;
|
||||
|
||||
if (productTypeSelect != null) {
|
||||
data['productTypeSelect'] = productTypeSelect; // ✅ must be int
|
||||
}
|
||||
|
||||
// ✅ Axelor expects {"id": X}, NOT raw int
|
||||
if (familleProduit != null) {
|
||||
data['familleProduit'] = {'id': familleProduit};
|
||||
}
|
||||
if (sousFamilleProduit != null) {
|
||||
data['sousFamilleProduit'] = {'id': sousFamilleProduit};
|
||||
}
|
||||
|
||||
data['internalDescription'] = internalDescription;
|
||||
data['serialNumber'] = serialNumber;
|
||||
data['description'] = description;
|
||||
data['procurementMethodSelect'] = procurementMethodSelect;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Product{unit: $unit, code: $code, name: $name, id: $id, version: $version, productTypeSelect: $productTypeSelect, familleProduit: $familleProduit, sousFamilleProduit: $sousFamilleProduit, internalDescription: $internalDescription, serialNumber: $serialNumber, description: $description}';
|
||||
}
|
||||
|
||||
/// 👇 Get full image URL (you can customize baseUrl to be from `AxelorClient.baseUrl`)
|
||||
String? get imageUrl {
|
||||
if (picture?.id != null) {
|
||||
return '${Utils.url}/ws/rest/com.axelor.meta.db.MetaFile/${picture!.id}/content/download';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class Unit {
|
||||
String? name;
|
||||
int? id;
|
||||
int? version;
|
||||
|
||||
Unit({this.name, this.id, this.version});
|
||||
|
||||
Unit.fromJson(Map<String, dynamic> json) {
|
||||
name = json['name'];
|
||||
id = json['id'];
|
||||
version = json['version'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {'name': name, 'id': id, 'version': version};
|
||||
}
|
||||
}
|
||||
|
||||
class MetaFile {
|
||||
String? fileName;
|
||||
int? id;
|
||||
int? version;
|
||||
|
||||
MetaFile({this.fileName, this.id, this.version});
|
||||
|
||||
MetaFile.fromJson(Map<String, dynamic> json) {
|
||||
fileName = json['fileName'];
|
||||
id = json['id'];
|
||||
version = json['$version'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {'fileName': fileName, 'id': id, '\$version': version};
|
||||
}
|
||||
}
|
||||
52
lib/models/profile.dart
Normal file
52
lib/models/profile.dart
Normal file
@@ -0,0 +1,52 @@
|
||||
class Profile {
|
||||
String? validId;
|
||||
String? glpiCurrenttime;
|
||||
int? glpiUseMode;
|
||||
int? glpiID;
|
||||
String? glpiisIdsVisible;
|
||||
String? glpifriendlyname;
|
||||
String? glpiname;
|
||||
String? glpirealname;
|
||||
String? glpifirstname;
|
||||
int? glpidefaultEntity;
|
||||
|
||||
Profile(
|
||||
{this.validId,
|
||||
this.glpiCurrenttime,
|
||||
this.glpiUseMode,
|
||||
this.glpiID,
|
||||
this.glpiisIdsVisible,
|
||||
this.glpifriendlyname,
|
||||
this.glpiname,
|
||||
this.glpirealname,
|
||||
this.glpifirstname,
|
||||
this.glpidefaultEntity});
|
||||
|
||||
Profile.fromJson(Map<String, dynamic> json) {
|
||||
validId = json['valid_id'];
|
||||
glpiCurrenttime = json['glpi_currenttime'];
|
||||
glpiUseMode = json['glpi_use_mode'];
|
||||
glpiID = json['glpiID'];
|
||||
glpiisIdsVisible = json['glpiis_ids_visible'];
|
||||
glpifriendlyname = json['glpifriendlyname'];
|
||||
glpiname = json['glpiname'];
|
||||
glpirealname = json['glpirealname'];
|
||||
glpifirstname = json['glpifirstname'];
|
||||
glpidefaultEntity = json['glpidefault_entity'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['valid_id'] = validId;
|
||||
data['glpi_currenttime'] = glpiCurrenttime;
|
||||
data['glpi_use_mode'] = glpiUseMode;
|
||||
data['glpiID'] = glpiID;
|
||||
data['glpiis_ids_visible'] = glpiisIdsVisible;
|
||||
data['glpifriendlyname'] = glpifriendlyname;
|
||||
data['glpiname'] = glpiname;
|
||||
data['glpirealname'] = glpirealname;
|
||||
data['glpifirstname'] = glpifirstname;
|
||||
data['glpidefault_entity'] = glpidefaultEntity;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
35
lib/models/tracking_number.dart
Normal file
35
lib/models/tracking_number.dart
Normal file
@@ -0,0 +1,35 @@
|
||||
import 'package:inventory_app/models/product.dart';
|
||||
|
||||
class TrackingNumber {
|
||||
int? id;
|
||||
int? version;
|
||||
String? trackingNumberSeq;
|
||||
String? perishableExpirationDate;
|
||||
Product? product;
|
||||
|
||||
TrackingNumber({
|
||||
this.id,
|
||||
this.version,
|
||||
this.trackingNumberSeq,
|
||||
this.perishableExpirationDate,
|
||||
this.product,
|
||||
});
|
||||
|
||||
TrackingNumber.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
version = json['version'];
|
||||
trackingNumberSeq = json['trackingNumberSeq'];
|
||||
perishableExpirationDate = json['perishableExpirationDate'];
|
||||
product = json['product'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['id'] = this.id;
|
||||
data['version'] = this.version;
|
||||
data['trackingNumberSeq'] = this.trackingNumberSeq;
|
||||
data['perishableExpirationDate'] = this.perishableExpirationDate;
|
||||
data['product'] = this.product;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user