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:
BACHIR SOULDI
2026-07-16 14:37:28 +01:00
parent 37b0762921
commit 5a483da01d
110 changed files with 8081 additions and 0 deletions

110
lib/models/depot.dart Normal file
View 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};
}
}

View 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;
}

View 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
View 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
View 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;
}
}

View 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;
}
}