item level change
This commit is contained in:
parent
3914e78465
commit
36847aaf87
@ -56,8 +56,6 @@ class ApiEndpoints {
|
|||||||
'/masters/item-subcategories/$id';
|
'/masters/item-subcategories/$id';
|
||||||
static const String items = '/masters/items';
|
static const String items = '/masters/items';
|
||||||
static String itemById(String id) => '/masters/items/$id';
|
static String itemById(String id) => '/masters/items/$id';
|
||||||
static const String brands = '/masters/brands';
|
|
||||||
static String brandById(String id) => '/masters/brands/$id';
|
|
||||||
static const String documentSeries = '/masters/document-series';
|
static const String documentSeries = '/masters/document-series';
|
||||||
static String documentSeriesById(String id) => '/masters/document-series/$id';
|
static String documentSeriesById(String id) => '/masters/document-series/$id';
|
||||||
static const String deliveryTerms = '/masters/delivery-terms';
|
static const String deliveryTerms = '/masters/delivery-terms';
|
||||||
|
|||||||
@ -104,10 +104,20 @@ class AssetRemoteDataSource {
|
|||||||
return _parseList(response.data, AssetTransferHistoryModel.fromJson);
|
return _parseList(response.data, AssetTransferHistoryModel.fromJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<AssetCategoryModel>> getCategories() async {
|
Future<List<AssetCategoryModel>> getCategories({
|
||||||
|
bool dropdownCall = false,
|
||||||
|
}) async {
|
||||||
final response = await dio.get(
|
final response = await dio.get(
|
||||||
ApiEndpoints.itemCategories,
|
ApiEndpoints.itemCategories,
|
||||||
queryParameters: const {'limit': 100, 'is_active': true},
|
queryParameters: {
|
||||||
|
if (dropdownCall)
|
||||||
|
'dropdown_call': true
|
||||||
|
else ...const {
|
||||||
|
'limit': 100,
|
||||||
|
'is_active': true,
|
||||||
|
},
|
||||||
|
'category_type': 'ASSET',
|
||||||
|
},
|
||||||
);
|
);
|
||||||
return _parseList(response.data, AssetCategoryModel.fromJson)
|
return _parseList(response.data, AssetCategoryModel.fromJson)
|
||||||
.where((category) => category.isActive)
|
.where((category) => category.isActive)
|
||||||
|
|||||||
@ -63,8 +63,10 @@ class AssetRepositoryImpl implements AssetRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<List<AssetCategoryModel>>> getCategories() {
|
Future<Result<List<AssetCategoryModel>>> getCategories({
|
||||||
return safeApiCall(() => dataSource.getCategories());
|
bool dropdownCall = false,
|
||||||
|
}) {
|
||||||
|
return safeApiCall(() => dataSource.getCategories(dropdownCall: dropdownCall));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -13,7 +13,9 @@ abstract class AssetRepository {
|
|||||||
Future<Result<void>> deleteAsset(String id);
|
Future<Result<void>> deleteAsset(String id);
|
||||||
Future<Result<void>> transferAsset(String id, Map<String, dynamic> data);
|
Future<Result<void>> transferAsset(String id, Map<String, dynamic> data);
|
||||||
Future<Result<List<AssetTransferHistoryModel>>> getTransferHistory(String assetId);
|
Future<Result<List<AssetTransferHistoryModel>>> getTransferHistory(String assetId);
|
||||||
Future<Result<List<AssetCategoryModel>>> getCategories();
|
Future<Result<List<AssetCategoryModel>>> getCategories({
|
||||||
|
bool dropdownCall = false,
|
||||||
|
});
|
||||||
Future<Result<AssetDropdownOptionsModel>> getAssetOptions();
|
Future<Result<AssetDropdownOptionsModel>> getAssetOptions();
|
||||||
Future<Result<List<AssetDropdownOption>>> getContractTypes();
|
Future<Result<List<AssetDropdownOption>>> getContractTypes();
|
||||||
Future<Result<List<AssetDropdownOption>>> getVisitTypes();
|
Future<Result<List<AssetDropdownOption>>> getVisitTypes();
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||||||
import '../../data/repositories/asset_repository_impl.dart';
|
import '../../data/repositories/asset_repository_impl.dart';
|
||||||
import '../../../../shared/models/asset_model.dart';
|
import '../../../../shared/models/asset_model.dart';
|
||||||
|
|
||||||
/// Item categories from `/masters/item-categories` (shared for items and assets).
|
/// Categories for Assets list filter (paginated list API — no dropdown_call).
|
||||||
final itemCategoriesProvider = FutureProvider<List<AssetCategoryModel>>((ref) async {
|
final itemCategoriesProvider = FutureProvider<List<AssetCategoryModel>>((ref) async {
|
||||||
final repository = ref.watch(assetRepositoryProvider);
|
final repository = ref.watch(assetRepositoryProvider);
|
||||||
final result = await repository.getCategories();
|
final result = await repository.getCategories();
|
||||||
@ -11,5 +11,14 @@ final itemCategoriesProvider = FutureProvider<List<AssetCategoryModel>>((ref) as
|
|||||||
return result.data ?? [];
|
return result.data ?? [];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Categories for Asset form dropdowns (`dropdown_call=true`).
|
||||||
|
final itemCategoriesFormProvider =
|
||||||
|
FutureProvider<List<AssetCategoryModel>>((ref) async {
|
||||||
|
final repository = ref.watch(assetRepositoryProvider);
|
||||||
|
final result = await repository.getCategories(dropdownCall: true);
|
||||||
|
if (result.failure != null) throw result.failure!;
|
||||||
|
return result.data ?? [];
|
||||||
|
});
|
||||||
|
|
||||||
@Deprecated('Use itemCategoriesProvider')
|
@Deprecated('Use itemCategoriesProvider')
|
||||||
final assetCategoriesProvider = itemCategoriesProvider;
|
final assetCategoriesProvider = itemCategoriesProvider;
|
||||||
|
|||||||
@ -1,19 +1,15 @@
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import '../../../../core/constants/app_constants.dart';
|
|
||||||
import '../../../../core/network/api_handler.dart';
|
import '../../../../core/network/api_handler.dart';
|
||||||
import '../../../../core/utils/active_option.dart';
|
import '../../../../core/utils/active_option.dart';
|
||||||
import '../../../../shared/models/asset_model.dart';
|
import '../../../../shared/models/asset_model.dart';
|
||||||
import '../../../../shared/models/grn_model.dart';
|
|
||||||
import '../../../../shared/models/purchase_order_model.dart';
|
|
||||||
import '../../../../shared/models/user_management_models.dart';
|
import '../../../../shared/models/user_management_models.dart';
|
||||||
import '../../../../shared/models/vendor_model.dart';
|
|
||||||
import '../../../../shared/widgets/app_dropdown.dart';
|
import '../../../../shared/widgets/app_dropdown.dart';
|
||||||
import '../../../assets/data/repositories/asset_repository_impl.dart';
|
import '../../../assets/data/repositories/asset_repository_impl.dart';
|
||||||
import '../../../grn/data/repositories/grn_repository_impl.dart';
|
import '../../../grn/data/repositories/grn_repository_impl.dart';
|
||||||
import '../../../masters/data/datasources/master_remote_data_source.dart';
|
import '../../../masters/data/datasources/master_remote_data_source.dart';
|
||||||
import '../../../purchase_orders/data/repositories/purchase_order_repository_impl.dart';
|
import '../../../purchase_orders/data/repositories/purchase_order_repository_impl.dart';
|
||||||
import '../../../users/presentation/providers/users_provider.dart';
|
import '../../../users/data/repositories/user_repository_impl.dart';
|
||||||
import '../../../vendors/data/repositories/vendor_repository_impl.dart';
|
import '../../../vendors/data/repositories/vendor_repository_impl.dart';
|
||||||
|
|
||||||
class AssetFormLookups {
|
class AssetFormLookups {
|
||||||
@ -117,41 +113,24 @@ Future<List<FilterOptionModel>> _safeOptions(
|
|||||||
|
|
||||||
Future<List<FilterOptionModel>> _safeVendorOptions(Ref ref) async {
|
Future<List<FilterOptionModel>> _safeVendorOptions(Ref ref) async {
|
||||||
try {
|
try {
|
||||||
final vendors = <FilterOptionModel>[];
|
final result =
|
||||||
var page = 1;
|
await ref.read(vendorRepositoryProvider).listVendorOptions();
|
||||||
var totalPages = 1;
|
if (result.failure != null || result.data == null) return const [];
|
||||||
|
|
||||||
while (page <= totalPages) {
|
return result.data!
|
||||||
final result = await ref.read(vendorRepositoryProvider).getVendors(
|
.where(
|
||||||
VendorListQuery(
|
(vendor) => isActiveVendorOption(
|
||||||
page: page,
|
isActive: vendor.isActive,
|
||||||
limit: AppConstants.maxPageSize,
|
status: vendor.status,
|
||||||
isActive: true,
|
),
|
||||||
),
|
)
|
||||||
);
|
.map(
|
||||||
if (result.failure != null || result.data == null) return vendors;
|
(vendor) => FilterOptionModel(
|
||||||
|
id: vendor.id,
|
||||||
final data = result.data!;
|
name: vendor.vendorName,
|
||||||
vendors.addAll(
|
),
|
||||||
data.items
|
)
|
||||||
.where(
|
.toList();
|
||||||
(vendor) => isActiveVendorOption(
|
|
||||||
isActive: vendor.isActive,
|
|
||||||
status: vendor.status,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.map(
|
|
||||||
(vendor) => FilterOptionModel(
|
|
||||||
id: vendor.id,
|
|
||||||
name: vendor.vendorName,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
totalPages = data.totalPages;
|
|
||||||
page++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return vendors;
|
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return const [];
|
return const [];
|
||||||
}
|
}
|
||||||
@ -159,16 +138,9 @@ Future<List<FilterOptionModel>> _safeVendorOptions(Ref ref) async {
|
|||||||
|
|
||||||
Future<List<FilterOptionModel>> _safeUserOptions(Ref ref) async {
|
Future<List<FilterOptionModel>> _safeUserOptions(Ref ref) async {
|
||||||
try {
|
try {
|
||||||
final result = await ref.read(getUsersUseCaseProvider)(
|
final result = await ref.read(userRepositoryProvider).listUserOptions();
|
||||||
const UserListQuery(
|
|
||||||
page: 1,
|
|
||||||
limit: AppConstants.maxPageSize,
|
|
||||||
status: 'active',
|
|
||||||
isActive: true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (result.failure != null || result.data == null) return const [];
|
if (result.failure != null || result.data == null) return const [];
|
||||||
return result.data!.items
|
return result.data!
|
||||||
.where(
|
.where(
|
||||||
(user) => isActiveUserOption(
|
(user) => isActiveUserOption(
|
||||||
status: user.status,
|
status: user.status,
|
||||||
@ -189,15 +161,11 @@ Future<List<FilterOptionModel>> _safeUserOptions(Ref ref) async {
|
|||||||
|
|
||||||
Future<List<FilterOptionModel>> _safePurchaseOrderOptions(Ref ref) async {
|
Future<List<FilterOptionModel>> _safePurchaseOrderOptions(Ref ref) async {
|
||||||
try {
|
try {
|
||||||
final result =
|
final result = await ref
|
||||||
await ref.read(purchaseOrderRepositoryProvider).getPurchaseOrders(
|
.read(purchaseOrderRepositoryProvider)
|
||||||
const PurchaseOrderListQuery(
|
.listPurchaseOrderOptions();
|
||||||
page: 1,
|
|
||||||
limit: AppConstants.maxPageSize,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (result.failure != null || result.data == null) return const [];
|
if (result.failure != null || result.data == null) return const [];
|
||||||
return result.data!.items
|
return result.data!
|
||||||
.map(
|
.map(
|
||||||
(po) => FilterOptionModel(
|
(po) => FilterOptionModel(
|
||||||
id: po.id,
|
id: po.id,
|
||||||
@ -212,11 +180,9 @@ Future<List<FilterOptionModel>> _safePurchaseOrderOptions(Ref ref) async {
|
|||||||
|
|
||||||
Future<List<FilterOptionModel>> _safeGrnOptions(Ref ref) async {
|
Future<List<FilterOptionModel>> _safeGrnOptions(Ref ref) async {
|
||||||
try {
|
try {
|
||||||
final result = await ref.read(grnRepositoryProvider).getGrns(
|
final result = await ref.read(grnRepositoryProvider).listGrnOptions();
|
||||||
const GrnListQuery(page: 1, limit: AppConstants.maxPageSize),
|
|
||||||
);
|
|
||||||
if (result.failure != null || result.data == null) return const [];
|
if (result.failure != null || result.data == null) return const [];
|
||||||
return result.data!.items
|
return result.data!
|
||||||
.map(
|
.map(
|
||||||
(grn) => FilterOptionModel(
|
(grn) => FilterOptionModel(
|
||||||
id: grn.id,
|
id: grn.id,
|
||||||
|
|||||||
@ -466,7 +466,7 @@ class _AssetFormPanelState extends ConsumerState<AssetFormPanel> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final categoriesAsync = ref.watch(itemCategoriesProvider);
|
final categoriesAsync = ref.watch(itemCategoriesFormProvider);
|
||||||
final plantsAsync = ref.watch(assetPlantsProvider);
|
final plantsAsync = ref.watch(assetPlantsProvider);
|
||||||
|
|
||||||
if (widget.isEditing) {
|
if (widget.isEditing) {
|
||||||
@ -1091,6 +1091,7 @@ class _AssetFormPanelState extends ConsumerState<AssetFormPanel> {
|
|||||||
value: _dropdownValue(_categoryId, categoryIds),
|
value: _dropdownValue(_categoryId, categoryIds),
|
||||||
searchHint: 'Search category...',
|
searchHint: 'Search category...',
|
||||||
isDense: true,
|
isDense: true,
|
||||||
|
initialValues: const {'category_type': 'ASSET'},
|
||||||
options: activeCategories
|
options: activeCategories
|
||||||
.map(
|
.map(
|
||||||
(c) => AppDropdownOption(
|
(c) => AppDropdownOption(
|
||||||
@ -1101,7 +1102,7 @@ class _AssetFormPanelState extends ConsumerState<AssetFormPanel> {
|
|||||||
.where((option) => option.value != 0)
|
.where((option) => option.value != 0)
|
||||||
.toList(),
|
.toList(),
|
||||||
refreshLookups: () {
|
refreshLookups: () {
|
||||||
ref.invalidate(itemCategoriesProvider);
|
ref.invalidate(itemCategoriesFormProvider);
|
||||||
},
|
},
|
||||||
parseCreatedId: int.tryParse,
|
parseCreatedId: int.tryParse,
|
||||||
onChanged: (v) => setState(() {
|
onChanged: (v) => setState(() {
|
||||||
|
|||||||
@ -19,6 +19,26 @@ class GrnRemoteDataSource {
|
|||||||
return _parsePaginated(response.data, GrnModel.fromJson);
|
return _parsePaginated(response.data, GrnModel.fromJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Form-dropdown loader: all active GRNs (`dropdown_call=true`).
|
||||||
|
Future<List<GrnModel>> listGrnOptions() async {
|
||||||
|
final response = await dio.get(
|
||||||
|
ApiEndpoints.grn,
|
||||||
|
queryParameters: const {'dropdown_call': true},
|
||||||
|
);
|
||||||
|
final body = response.data;
|
||||||
|
if (body is! Map) return const [];
|
||||||
|
final raw = body['data'];
|
||||||
|
final list = raw is List
|
||||||
|
? raw
|
||||||
|
: raw is Map
|
||||||
|
? (raw['items'] as List?) ?? const []
|
||||||
|
: const [];
|
||||||
|
return list
|
||||||
|
.whereType<Map>()
|
||||||
|
.map((item) => GrnModel.fromJson(Map<String, dynamic>.from(item)))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
Future<GrnModel> getGrnById(String id) async {
|
Future<GrnModel> getGrnById(String id) async {
|
||||||
final response = await dio.get(ApiEndpoints.grnById(id));
|
final response = await dio.get(ApiEndpoints.grnById(id));
|
||||||
return GrnModel.fromJson(response.data['data'] as Map<String, dynamic>);
|
return GrnModel.fromJson(response.data['data'] as Map<String, dynamic>);
|
||||||
|
|||||||
@ -26,6 +26,11 @@ class GrnRepositoryImpl implements GrnRepository {
|
|||||||
return safeApiCall(() => dataSource.getGrns(query));
|
return safeApiCall(() => dataSource.getGrns(query));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<List<GrnModel>>> listGrnOptions() {
|
||||||
|
return safeApiCall(() => dataSource.listGrnOptions());
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<ExportFileResult>> exportGrns(GrnListQuery query) {
|
Future<Result<ExportFileResult>> exportGrns(GrnListQuery query) {
|
||||||
return safeApiCall(() => dataSource.exportGrns(query));
|
return safeApiCall(() => dataSource.exportGrns(query));
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import '../../../../shared/models/grn_model.dart';
|
|||||||
|
|
||||||
abstract class GrnRepository {
|
abstract class GrnRepository {
|
||||||
Future<Result<PaginatedResponse<GrnModel>>> getGrns(GrnListQuery query);
|
Future<Result<PaginatedResponse<GrnModel>>> getGrns(GrnListQuery query);
|
||||||
|
Future<Result<List<GrnModel>>> listGrnOptions();
|
||||||
Future<Result<ExportFileResult>> exportGrns(GrnListQuery query);
|
Future<Result<ExportFileResult>> exportGrns(GrnListQuery query);
|
||||||
Future<Result<GrnModel>> getGrnById(String id);
|
Future<Result<GrnModel>> getGrnById(String id);
|
||||||
Future<Result<GrnModel>> createGrn(Map<String, dynamic> data);
|
Future<Result<GrnModel>> createGrn(Map<String, dynamic> data);
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import '../../../../core/constants/app_constants.dart';
|
|
||||||
import '../../../../core/utils/active_option.dart';
|
import '../../../../core/utils/active_option.dart';
|
||||||
import '../../../../shared/models/purchase_order_model.dart';
|
import '../../../../shared/models/purchase_order_model.dart';
|
||||||
import '../../../../shared/models/user_management_models.dart';
|
import '../../../../shared/models/user_management_models.dart';
|
||||||
import '../../../masters/data/datasources/master_remote_data_source.dart';
|
import '../../../masters/data/datasources/master_remote_data_source.dart';
|
||||||
import '../../../purchase_orders/data/repositories/purchase_order_repository_impl.dart';
|
import '../../../purchase_orders/data/repositories/purchase_order_repository_impl.dart';
|
||||||
import '../../../users/presentation/providers/users_provider.dart';
|
import '../../../users/data/repositories/user_repository_impl.dart';
|
||||||
|
|
||||||
class GrnLookups {
|
class GrnLookups {
|
||||||
const GrnLookups({
|
const GrnLookups({
|
||||||
@ -29,15 +28,9 @@ final grnLookupsProvider = FutureProvider.autoDispose<GrnLookups>((ref) async {
|
|||||||
|
|
||||||
final receivablePos = <PurchaseOrderModel>[];
|
final receivablePos = <PurchaseOrderModel>[];
|
||||||
for (final status in ['APPROVED', 'PARTIALLY_RECEIVED']) {
|
for (final status in ['APPROVED', 'PARTIALLY_RECEIVED']) {
|
||||||
final result = await poRepo.getPurchaseOrders(
|
final result = await poRepo.listPurchaseOrderOptions(status: status);
|
||||||
PurchaseOrderListQuery(
|
|
||||||
page: 1,
|
|
||||||
limit: AppConstants.maxPageSize,
|
|
||||||
status: status,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (result.failure == null && result.data != null) {
|
if (result.failure == null && result.data != null) {
|
||||||
receivablePos.addAll(result.data!.items);
|
receivablePos.addAll(result.data!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,16 +53,9 @@ Future<List<FilterOptionModel>> _safeOptions(
|
|||||||
|
|
||||||
Future<List<FilterOptionModel>> _safeUserOptions(Ref ref) async {
|
Future<List<FilterOptionModel>> _safeUserOptions(Ref ref) async {
|
||||||
try {
|
try {
|
||||||
final result = await ref.read(getUsersUseCaseProvider)(
|
final result = await ref.read(userRepositoryProvider).listUserOptions();
|
||||||
const UserListQuery(
|
|
||||||
page: 1,
|
|
||||||
limit: AppConstants.maxPageSize,
|
|
||||||
status: 'active',
|
|
||||||
isActive: true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (result.failure != null || result.data == null) return const [];
|
if (result.failure != null || result.data == null) return const [];
|
||||||
return result.data!.items
|
return result.data!
|
||||||
.where(
|
.where(
|
||||||
(user) => isActiveUserOption(
|
(user) => isActiveUserOption(
|
||||||
status: user.status,
|
status: user.status,
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import '../../../../core/constants/app_constants.dart';
|
|
||||||
import '../../../../core/network/dio_client.dart';
|
import '../../../../core/network/dio_client.dart';
|
||||||
import '../../../../core/utils/active_option.dart';
|
import '../../../../core/utils/active_option.dart';
|
||||||
import '../../../../shared/models/export_file_result.dart';
|
import '../../../../shared/models/export_file_result.dart';
|
||||||
@ -43,6 +42,7 @@ class MasterCrudRemoteDataSource {
|
|||||||
int limit = 20,
|
int limit = 20,
|
||||||
String? search,
|
String? search,
|
||||||
bool? isActive,
|
bool? isActive,
|
||||||
|
Map<String, dynamic>? extraQueryParameters,
|
||||||
}) async {
|
}) async {
|
||||||
final response = await dio.get(
|
final response = await dio.get(
|
||||||
definition.apiPath,
|
definition.apiPath,
|
||||||
@ -51,6 +51,7 @@ class MasterCrudRemoteDataSource {
|
|||||||
'limit': limit,
|
'limit': limit,
|
||||||
if (search != null && search.isNotEmpty) 'search': search,
|
if (search != null && search.isNotEmpty) 'search': search,
|
||||||
if (isActive != null) 'is_active': isActive,
|
if (isActive != null) 'is_active': isActive,
|
||||||
|
...?extraQueryParameters,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -80,21 +81,31 @@ class MasterCrudRemoteDataSource {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Map<String, dynamic>>> listOptions(MasterDefinition definition) async {
|
Future<List<Map<String, dynamic>>> listOptions(
|
||||||
final allItems = <Map<String, dynamic>>[];
|
MasterDefinition definition, {
|
||||||
var page = 1;
|
Map<String, dynamic>? queryParameters,
|
||||||
while (true) {
|
}) async {
|
||||||
final result = await list(
|
final response = await dio.get(
|
||||||
definition,
|
definition.apiPath,
|
||||||
page: page,
|
queryParameters: {
|
||||||
limit: AppConstants.defaultPageSize,
|
'dropdown_call': true,
|
||||||
isActive: true,
|
...?queryParameters,
|
||||||
);
|
},
|
||||||
allItems.addAll(result.items.where(isActiveOptionRow));
|
);
|
||||||
if (page >= result.totalPages) break;
|
|
||||||
page++;
|
final body = response.data as Map<String, dynamic>;
|
||||||
}
|
final raw = body['data'];
|
||||||
return allItems;
|
final list = raw is List<dynamic>
|
||||||
|
? raw
|
||||||
|
: raw is Map<String, dynamic>
|
||||||
|
? raw['items'] as List<dynamic>? ?? const []
|
||||||
|
: const [];
|
||||||
|
|
||||||
|
return list
|
||||||
|
.whereType<Map>()
|
||||||
|
.map((item) => Map<String, dynamic>.from(item))
|
||||||
|
.where(isActiveOptionRow)
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> getById(
|
Future<Map<String, dynamic>> getById(
|
||||||
|
|||||||
@ -33,9 +33,12 @@ class MasterRepositoryImpl implements MasterRepository {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<List<Map<String, dynamic>>>> listOptions(
|
Future<Result<List<Map<String, dynamic>>>> listOptions(
|
||||||
MasterDefinition definition,
|
MasterDefinition definition, {
|
||||||
) =>
|
Map<String, dynamic>? queryParameters,
|
||||||
safeApiCall(() => remote.listOptions(definition));
|
}) =>
|
||||||
|
safeApiCall(
|
||||||
|
() => remote.listOptions(definition, queryParameters: queryParameters),
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<Map<String, dynamic>>> getById(
|
Future<Result<Map<String, dynamic>>> getById(
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
|
|
||||||
enum MasterFieldType { text, number, boolean, dropdown }
|
enum MasterFieldType { text, number, boolean, dropdown }
|
||||||
|
|
||||||
const brandTypes = ['OWN', 'OEM', 'THIRD_PARTY'];
|
const categoryTypeOptions = ['STOCK', 'ASSET'];
|
||||||
|
|
||||||
class MasterFieldDef {
|
class MasterFieldDef {
|
||||||
const MasterFieldDef({
|
const MasterFieldDef({
|
||||||
@ -12,11 +12,15 @@ class MasterFieldDef {
|
|||||||
this.required = false,
|
this.required = false,
|
||||||
this.showInList = false,
|
this.showInList = false,
|
||||||
this.showInForm = true,
|
this.showInForm = true,
|
||||||
|
this.readOnly = false,
|
||||||
this.optionsMasterKey,
|
this.optionsMasterKey,
|
||||||
|
this.optionsQueryParams,
|
||||||
this.staticOptions,
|
this.staticOptions,
|
||||||
this.multiline = false,
|
this.multiline = false,
|
||||||
this.filterByFieldKey,
|
this.filterByFieldKey,
|
||||||
this.filterByOptionKey,
|
this.filterByOptionKey,
|
||||||
|
this.visibleWhenFieldKey,
|
||||||
|
this.visibleWhenValue,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String key;
|
final String key;
|
||||||
@ -26,15 +30,40 @@ class MasterFieldDef {
|
|||||||
final bool showInList;
|
final bool showInList;
|
||||||
/// When false, field is list/display-only and excluded from create/update payloads.
|
/// When false, field is list/display-only and excluded from create/update payloads.
|
||||||
final bool showInForm;
|
final bool showInForm;
|
||||||
|
/// When true, shown in the form but not editable (value set by other fields).
|
||||||
|
final bool readOnly;
|
||||||
/// Master key used to populate dropdown options (e.g. `plants` for plant_id).
|
/// Master key used to populate dropdown options (e.g. `plants` for plant_id).
|
||||||
final String? optionsMasterKey;
|
final String? optionsMasterKey;
|
||||||
/// Fixed dropdown choices (e.g. brand type) — no API lookup.
|
/// Extra query parameters when loading [optionsMasterKey] options.
|
||||||
|
final Map<String, dynamic>? optionsQueryParams;
|
||||||
|
/// Fixed dropdown choices (e.g. category type) — no API lookup.
|
||||||
final List<String>? staticOptions;
|
final List<String>? staticOptions;
|
||||||
final bool multiline;
|
final bool multiline;
|
||||||
/// Form field whose value filters this dropdown (e.g. `item_category_id`).
|
/// Form field whose value filters this dropdown (e.g. `item_category_id`).
|
||||||
final String? filterByFieldKey;
|
final String? filterByFieldKey;
|
||||||
/// Option-row key matched against [filterByFieldKey] (defaults to same key).
|
/// Option-row key matched against [filterByFieldKey] (defaults to same key).
|
||||||
final String? filterByOptionKey;
|
final String? filterByOptionKey;
|
||||||
|
/// Show this field only when [visibleWhenFieldKey] equals [visibleWhenValue].
|
||||||
|
final String? visibleWhenFieldKey;
|
||||||
|
final String? visibleWhenValue;
|
||||||
|
|
||||||
|
/// Cache key for dropdown option rows (includes query params when set).
|
||||||
|
String get dropdownLookupKey {
|
||||||
|
final masterKey = optionsMasterKey;
|
||||||
|
if (masterKey == null) return key;
|
||||||
|
final params = optionsQueryParams;
|
||||||
|
if (params == null || params.isEmpty) return masterKey;
|
||||||
|
final parts = params.entries.toList()
|
||||||
|
..sort((a, b) => a.key.compareTo(b.key));
|
||||||
|
final query = parts.map((e) => '${e.key}=${e.value}').join('&');
|
||||||
|
return '$masterKey?$query';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isVisibleInForm(Map<String, dynamic> values) {
|
||||||
|
final whenKey = visibleWhenFieldKey;
|
||||||
|
if (whenKey == null) return true;
|
||||||
|
return values[whenKey]?.toString() == visibleWhenValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MasterDefinition {
|
class MasterDefinition {
|
||||||
@ -119,11 +148,27 @@ const masterDefinitions = <MasterDefinition>[
|
|||||||
fields: [
|
fields: [
|
||||||
MasterFieldDef(key: 'code', label: 'Code', required: true, showInList: true),
|
MasterFieldDef(key: 'code', label: 'Code', required: true, showInList: true),
|
||||||
MasterFieldDef(key: 'name', label: 'Name', required: true, showInList: true),
|
MasterFieldDef(key: 'name', label: 'Name', required: true, showInList: true),
|
||||||
MasterFieldDef(key: 'code_prefix', label: 'Code Prefix', showInList: true),
|
MasterFieldDef(
|
||||||
|
key: 'category_type',
|
||||||
|
label: 'Category Type',
|
||||||
|
type: MasterFieldType.dropdown,
|
||||||
|
required: true,
|
||||||
|
showInList: true,
|
||||||
|
staticOptions: categoryTypeOptions,
|
||||||
|
),
|
||||||
|
MasterFieldDef(
|
||||||
|
key: 'code_prefix',
|
||||||
|
label: 'Code Prefix',
|
||||||
|
showInList: true,
|
||||||
|
visibleWhenFieldKey: 'category_type',
|
||||||
|
visibleWhenValue: 'ASSET',
|
||||||
|
),
|
||||||
MasterFieldDef(
|
MasterFieldDef(
|
||||||
key: 'default_useful_life_years',
|
key: 'default_useful_life_years',
|
||||||
label: 'Useful Life (Years)',
|
label: 'Useful Life (Years)',
|
||||||
type: MasterFieldType.number,
|
type: MasterFieldType.number,
|
||||||
|
visibleWhenFieldKey: 'category_type',
|
||||||
|
visibleWhenValue: 'ASSET',
|
||||||
),
|
),
|
||||||
MasterFieldDef(
|
MasterFieldDef(
|
||||||
key: 'default_depreciation_method',
|
key: 'default_depreciation_method',
|
||||||
@ -131,6 +176,8 @@ const masterDefinitions = <MasterDefinition>[
|
|||||||
type: MasterFieldType.dropdown,
|
type: MasterFieldType.dropdown,
|
||||||
showInList: true,
|
showInList: true,
|
||||||
optionsMasterKey: 'asset_depreciation_methods',
|
optionsMasterKey: 'asset_depreciation_methods',
|
||||||
|
visibleWhenFieldKey: 'category_type',
|
||||||
|
visibleWhenValue: 'ASSET',
|
||||||
),
|
),
|
||||||
_activeField,
|
_activeField,
|
||||||
],
|
],
|
||||||
@ -175,6 +222,12 @@ const masterDefinitions = <MasterDefinition>[
|
|||||||
showInList: true,
|
showInList: true,
|
||||||
showInForm: false,
|
showInForm: false,
|
||||||
),
|
),
|
||||||
|
MasterFieldDef(
|
||||||
|
key: 'is_asset_item',
|
||||||
|
label: 'Asset Item',
|
||||||
|
type: MasterFieldType.boolean,
|
||||||
|
required: true,
|
||||||
|
),
|
||||||
MasterFieldDef(key: 'item_name', label: 'Item Name', required: true, showInList: true),
|
MasterFieldDef(key: 'item_name', label: 'Item Name', required: true, showInList: true),
|
||||||
MasterFieldDef(
|
MasterFieldDef(
|
||||||
key: 'item_category_id',
|
key: 'item_category_id',
|
||||||
@ -182,6 +235,7 @@ const masterDefinitions = <MasterDefinition>[
|
|||||||
type: MasterFieldType.dropdown,
|
type: MasterFieldType.dropdown,
|
||||||
required: true,
|
required: true,
|
||||||
optionsMasterKey: 'item_categories',
|
optionsMasterKey: 'item_categories',
|
||||||
|
// Resolved at runtime from is_asset_item (STOCK / ASSET).
|
||||||
),
|
),
|
||||||
MasterFieldDef(
|
MasterFieldDef(
|
||||||
key: 'item_subcategory_id',
|
key: 'item_subcategory_id',
|
||||||
@ -208,19 +262,9 @@ const masterDefinitions = <MasterDefinition>[
|
|||||||
key: 'gst_rate_id',
|
key: 'gst_rate_id',
|
||||||
label: 'GST Rate',
|
label: 'GST Rate',
|
||||||
type: MasterFieldType.dropdown,
|
type: MasterFieldType.dropdown,
|
||||||
optionsMasterKey: 'gst_rates',
|
showInList: true,
|
||||||
),
|
readOnly: true,
|
||||||
MasterFieldDef(
|
// Filled from selected HSN's nested gst_rate — no gst-rates API.
|
||||||
key: 'brand_id',
|
|
||||||
label: 'Brand',
|
|
||||||
type: MasterFieldType.dropdown,
|
|
||||||
optionsMasterKey: 'brands',
|
|
||||||
),
|
|
||||||
MasterFieldDef(
|
|
||||||
key: 'is_asset_item',
|
|
||||||
label: 'Asset Item',
|
|
||||||
type: MasterFieldType.boolean,
|
|
||||||
required: true,
|
|
||||||
),
|
),
|
||||||
MasterFieldDef(
|
MasterFieldDef(
|
||||||
key: 'min_order_qty',
|
key: 'min_order_qty',
|
||||||
@ -257,32 +301,13 @@ const masterDefinitions = <MasterDefinition>[
|
|||||||
showInList: true,
|
showInList: true,
|
||||||
multiline: true,
|
multiline: true,
|
||||||
),
|
),
|
||||||
_activeField,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
MasterDefinition(
|
|
||||||
id: 'brands',
|
|
||||||
title: 'Brands',
|
|
||||||
subtitle: 'Own and third-party brands',
|
|
||||||
category: 'Inventory & Items',
|
|
||||||
routeKey: 'brands',
|
|
||||||
apiPath: '/masters/brands',
|
|
||||||
module: 'brands',
|
|
||||||
icon: Icons.loyalty_outlined,
|
|
||||||
fields: [
|
|
||||||
MasterFieldDef(key: 'code', label: 'Code', required: true, showInList: true),
|
|
||||||
MasterFieldDef(key: 'name', label: 'Name', required: true, showInList: true),
|
|
||||||
MasterFieldDef(
|
MasterFieldDef(
|
||||||
key: 'brand_type',
|
key: 'gst_rate_id',
|
||||||
label: 'Brand Type',
|
label: 'GST Rate',
|
||||||
type: MasterFieldType.dropdown,
|
type: MasterFieldType.dropdown,
|
||||||
required: true,
|
|
||||||
showInList: true,
|
showInList: true,
|
||||||
staticOptions: brandTypes,
|
optionsMasterKey: 'gst_rates',
|
||||||
),
|
),
|
||||||
MasterFieldDef(key: 'contact_person', label: 'Contact Person'),
|
|
||||||
MasterFieldDef(key: 'phone', label: 'Phone'),
|
|
||||||
MasterFieldDef(key: 'email', label: 'Email', required: true),
|
|
||||||
_activeField,
|
_activeField,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -504,6 +529,21 @@ String masterCellValue(Map<String, dynamic> row, MasterFieldDef field) {
|
|||||||
final label = row['${field.key}_label'];
|
final label = row['${field.key}_label'];
|
||||||
if (label != null && label.toString().isNotEmpty) return label.toString();
|
if (label != null && label.toString().isNotEmpty) return label.toString();
|
||||||
|
|
||||||
|
if (field.key == 'gst_rate_id') {
|
||||||
|
final nested = row['gst_rate'];
|
||||||
|
if (nested is Map) {
|
||||||
|
final pct = nested['rate_pct'];
|
||||||
|
if (pct != null) {
|
||||||
|
final rate = pct is num
|
||||||
|
? pct.toDouble()
|
||||||
|
: double.tryParse(pct.toString());
|
||||||
|
if (rate != null) {
|
||||||
|
return rate % 1 == 0 ? '${rate.toInt()}%' : '$rate%';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Prefer explicit "<base>_name" or nested "<base>.name" / flat code from API
|
// Prefer explicit "<base>_name" or nested "<base>.name" / flat code from API
|
||||||
// (e.g. asset_category_id -> asset_category_name; hsn_code_id -> hsn_code)
|
// (e.g. asset_category_id -> asset_category_name; hsn_code_id -> hsn_code)
|
||||||
if (field.key.endsWith('_id')) {
|
if (field.key.endsWith('_id')) {
|
||||||
@ -540,3 +580,61 @@ String masterStatusValue(Map<String, dynamic> row) {
|
|||||||
if (active == false) return 'inactive';
|
if (active == false) return 'inactive';
|
||||||
return 'active';
|
return 'active';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Category list filter for Items form: ASSET when Asset Item is checked.
|
||||||
|
String itemCategoryTypeForValues(Map<String, dynamic> values) =>
|
||||||
|
values['is_asset_item'] == true ? 'ASSET' : 'STOCK';
|
||||||
|
|
||||||
|
/// Effective options query for a form field (may depend on other values).
|
||||||
|
Map<String, dynamic>? masterFieldOptionsQuery({
|
||||||
|
required String masterId,
|
||||||
|
required MasterFieldDef field,
|
||||||
|
required Map<String, dynamic> values,
|
||||||
|
}) {
|
||||||
|
if (masterId == 'items' && field.key == 'item_category_id') {
|
||||||
|
return {'category_type': itemCategoryTypeForValues(values)};
|
||||||
|
}
|
||||||
|
return field.optionsQueryParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
String masterFieldDropdownLookupKey({
|
||||||
|
required String masterId,
|
||||||
|
required MasterFieldDef field,
|
||||||
|
required Map<String, dynamic> values,
|
||||||
|
}) {
|
||||||
|
final masterKey = field.optionsMasterKey;
|
||||||
|
if (masterKey == null) return field.key;
|
||||||
|
final params = masterFieldOptionsQuery(
|
||||||
|
masterId: masterId,
|
||||||
|
field: field,
|
||||||
|
values: values,
|
||||||
|
);
|
||||||
|
if (params == null || params.isEmpty) return masterKey;
|
||||||
|
final parts = params.entries.toList()
|
||||||
|
..sort((a, b) => a.key.compareTo(b.key));
|
||||||
|
final query = parts.map((e) => '${e.key}=${e.value}').join('&');
|
||||||
|
return '$masterKey?$query';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Display label for GST filled from HSN nested `gst_rate.description`.
|
||||||
|
String? gstRateDisplayFromValues(Map<String, dynamic> values) {
|
||||||
|
final nested = values['gst_rate'];
|
||||||
|
if (nested is Map) {
|
||||||
|
final desc = nested['description'];
|
||||||
|
if (desc != null && desc.toString().trim().isNotEmpty) {
|
||||||
|
return desc.toString().trim();
|
||||||
|
}
|
||||||
|
final pct = nested['rate_pct'];
|
||||||
|
if (pct != null) {
|
||||||
|
final rate = pct is num ? pct.toDouble() : double.tryParse(pct.toString());
|
||||||
|
if (rate != null) {
|
||||||
|
return rate % 1 == 0 ? '${rate.toInt()}%' : '$rate%';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final label = values['gst_rate_label'];
|
||||||
|
if (label != null && label.toString().trim().isNotEmpty) {
|
||||||
|
return label.toString().trim();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|||||||
@ -11,7 +11,10 @@ abstract class MasterRepository {
|
|||||||
String? search,
|
String? search,
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<Result<List<Map<String, dynamic>>>> listOptions(MasterDefinition definition);
|
Future<Result<List<Map<String, dynamic>>>> listOptions(
|
||||||
|
MasterDefinition definition, {
|
||||||
|
Map<String, dynamic>? queryParameters,
|
||||||
|
});
|
||||||
|
|
||||||
Future<Result<Map<String, dynamic>>> getById(
|
Future<Result<Map<String, dynamic>>> getById(
|
||||||
MasterDefinition definition,
|
MasterDefinition definition,
|
||||||
|
|||||||
@ -250,7 +250,6 @@ class MasterFormNotifier extends FamilyAsyncNotifier<MasterFormState, MasterForm
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<MasterFormState> build(MasterFormArgs arg) async {
|
Future<MasterFormState> build(MasterFormArgs arg) async {
|
||||||
final dropdownOptions = await _loadDropdownOptions();
|
|
||||||
final existingRecords = await _loadExistingRecords();
|
final existingRecords = await _loadExistingRecords();
|
||||||
Map<String, dynamic> values = {};
|
Map<String, dynamic> values = {};
|
||||||
|
|
||||||
@ -272,6 +271,18 @@ class MasterFormNotifier extends FamilyAsyncNotifier<MasterFormState, MasterForm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load after values so Items category options use is_asset_item.
|
||||||
|
final dropdownOptions = await _loadDropdownOptions(values: values);
|
||||||
|
|
||||||
|
if (_definition.id == 'items') {
|
||||||
|
final syncState = MasterFormState(
|
||||||
|
values: values,
|
||||||
|
dropdownOptions: dropdownOptions,
|
||||||
|
existingRecords: existingRecords,
|
||||||
|
);
|
||||||
|
_applyGstFromHsn(values, syncState);
|
||||||
|
}
|
||||||
|
|
||||||
return MasterFormState(
|
return MasterFormState(
|
||||||
values: values,
|
values: values,
|
||||||
dropdownOptions: dropdownOptions,
|
dropdownOptions: dropdownOptions,
|
||||||
@ -301,18 +312,25 @@ class MasterFormNotifier extends FamilyAsyncNotifier<MasterFormState, MasterForm
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, List<Map<String, dynamic>>>>
|
Future<Map<String, List<Map<String, dynamic>>>>
|
||||||
_loadDropdownOptions() async {
|
_loadDropdownOptions({Map<String, dynamic>? values}) async {
|
||||||
|
final formValues = values ?? state.valueOrNull?.values ?? const {};
|
||||||
final options = <String, List<Map<String, dynamic>>>{};
|
final options = <String, List<Map<String, dynamic>>>{};
|
||||||
final keys = _definition.formFields
|
final fields = _definition.formFields
|
||||||
.where((field) => field.optionsMasterKey != null)
|
.where((field) => field.optionsMasterKey != null);
|
||||||
.map((field) => field.optionsMasterKey!)
|
|
||||||
.toSet();
|
|
||||||
|
|
||||||
for (final key in keys) {
|
for (final field in fields) {
|
||||||
|
final lookupKey = masterFieldDropdownLookupKey(
|
||||||
|
masterId: _definition.id,
|
||||||
|
field: field,
|
||||||
|
values: formValues,
|
||||||
|
);
|
||||||
|
if (options.containsKey(lookupKey)) continue;
|
||||||
|
|
||||||
|
final key = field.optionsMasterKey!;
|
||||||
if (key == 'asset_depreciation_methods') {
|
if (key == 'asset_depreciation_methods') {
|
||||||
final result = await ref.read(assetRepositoryProvider).getDepreciationMethods();
|
final result = await ref.read(assetRepositoryProvider).getDepreciationMethods();
|
||||||
if (result.failure != null) continue;
|
if (result.failure != null) continue;
|
||||||
options[key] = (result.data ?? const [])
|
options[lookupKey] = (result.data ?? const [])
|
||||||
.where((option) => option.value.trim().isNotEmpty)
|
.where((option) => option.value.trim().isNotEmpty)
|
||||||
.map(
|
.map(
|
||||||
(option) => <String, dynamic>{
|
(option) => <String, dynamic>{
|
||||||
@ -326,19 +344,93 @@ class MasterFormNotifier extends FamilyAsyncNotifier<MasterFormState, MasterForm
|
|||||||
|
|
||||||
final def = masterDefinitionById(key);
|
final def = masterDefinitionById(key);
|
||||||
if (def == null) continue;
|
if (def == null) continue;
|
||||||
final result = await ref.read(masterRepositoryProvider).listOptions(def);
|
final queryParameters = masterFieldOptionsQuery(
|
||||||
|
masterId: _definition.id,
|
||||||
|
field: field,
|
||||||
|
values: formValues,
|
||||||
|
);
|
||||||
|
final result = await ref.read(masterRepositoryProvider).listOptions(
|
||||||
|
def,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
if (result.failure != null) continue;
|
if (result.failure != null) continue;
|
||||||
options[key] = result.data ?? const [];
|
options[lookupKey] = result.data ?? const [];
|
||||||
}
|
}
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _applyGstFromHsn(Map<String, dynamic> values, MasterFormState current) {
|
||||||
|
if (_definition.id != 'items') return;
|
||||||
|
final hsnId = values['hsn_code_id']?.toString();
|
||||||
|
if (hsnId == null || hsnId.isEmpty) {
|
||||||
|
values['gst_rate_id'] = null;
|
||||||
|
values['gst_rate'] = null;
|
||||||
|
values['gst_rate_label'] = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final hsnOptions = current.dropdownOptions['hsn_codes'] ?? const [];
|
||||||
|
Map<String, dynamic>? hsnRow;
|
||||||
|
for (final row in hsnOptions) {
|
||||||
|
if (row['id']?.toString() == hsnId) {
|
||||||
|
hsnRow = row;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hsnRow == null) return;
|
||||||
|
|
||||||
|
final nestedGst = hsnRow['gst_rate'];
|
||||||
|
final gstId = hsnRow['gst_rate_id'] ??
|
||||||
|
(nestedGst is Map ? nestedGst['id'] : null);
|
||||||
|
if (gstId != null && gstId.toString().isNotEmpty) {
|
||||||
|
values['gst_rate_id'] = gstId.toString();
|
||||||
|
} else {
|
||||||
|
values['gst_rate_id'] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nestedGst is Map) {
|
||||||
|
values['gst_rate'] = Map<String, dynamic>.from(nestedGst);
|
||||||
|
final desc = nestedGst['description'];
|
||||||
|
values['gst_rate_label'] =
|
||||||
|
desc != null && desc.toString().trim().isNotEmpty
|
||||||
|
? desc.toString().trim()
|
||||||
|
: gstRateDisplayFromValues(values);
|
||||||
|
} else {
|
||||||
|
values['gst_rate'] = null;
|
||||||
|
values['gst_rate_label'] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _clearHiddenFieldValues(Map<String, dynamic> values) {
|
||||||
|
for (final field in _definition.formFields) {
|
||||||
|
if (field.isVisibleInForm(values)) continue;
|
||||||
|
values[field.key] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void updateValue(String key, dynamic value) {
|
void updateValue(String key, dynamic value) {
|
||||||
final current = state.valueOrNull;
|
final current = state.valueOrNull;
|
||||||
if (current == null) return;
|
if (current == null) return;
|
||||||
final values = Map<String, dynamic>.from(current.values);
|
final values = Map<String, dynamic>.from(current.values);
|
||||||
values[key] = value;
|
values[key] = value;
|
||||||
|
|
||||||
|
if (key == 'hsn_code_id') {
|
||||||
|
_applyGstFromHsn(values, current);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == 'category_type') {
|
||||||
|
_clearHiddenFieldValues(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Asset Item toggles Items category list between STOCK / ASSET.
|
||||||
|
if (key == 'is_asset_item' && _definition.id == 'items') {
|
||||||
|
values['item_category_id'] = null;
|
||||||
|
values['item_subcategory_id'] = null;
|
||||||
|
state = AsyncData(current.copyWith(values: values));
|
||||||
|
_reloadItemCategoryOptions(values);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear dependent dropdowns when their parent filter value changes
|
// Clear dependent dropdowns when their parent filter value changes
|
||||||
// (e.g. item_category_id → item_subcategory_id).
|
// (e.g. item_category_id → item_subcategory_id).
|
||||||
for (final field in _definition.formFields) {
|
for (final field in _definition.formFields) {
|
||||||
@ -347,8 +439,12 @@ class MasterFormNotifier extends FamilyAsyncNotifier<MasterFormState, MasterForm
|
|||||||
if (dependentValue == null || dependentValue == '') continue;
|
if (dependentValue == null || dependentValue == '') continue;
|
||||||
|
|
||||||
final optionKey = field.filterByOptionKey ?? field.filterByFieldKey!;
|
final optionKey = field.filterByOptionKey ?? field.filterByFieldKey!;
|
||||||
final options =
|
final lookupKey = masterFieldDropdownLookupKey(
|
||||||
current.dropdownOptions[field.optionsMasterKey] ?? const [];
|
masterId: _definition.id,
|
||||||
|
field: field,
|
||||||
|
values: values,
|
||||||
|
);
|
||||||
|
final options = current.dropdownOptions[lookupKey] ?? const [];
|
||||||
final stillValid = options.any(
|
final stillValid = options.any(
|
||||||
(item) =>
|
(item) =>
|
||||||
item['id']?.toString() == dependentValue.toString() &&
|
item['id']?.toString() == dependentValue.toString() &&
|
||||||
@ -362,22 +458,35 @@ class MasterFormNotifier extends FamilyAsyncNotifier<MasterFormState, MasterForm
|
|||||||
state = AsyncData(current.copyWith(values: values));
|
state = AsyncData(current.copyWith(values: values));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _reloadItemCategoryOptions(Map<String, dynamic> values) async {
|
||||||
|
final current = state.valueOrNull;
|
||||||
|
if (current == null) return;
|
||||||
|
final options = await _loadDropdownOptions(values: values);
|
||||||
|
final latest = state.valueOrNull;
|
||||||
|
if (latest == null) return;
|
||||||
|
state = AsyncData(latest.copyWith(dropdownOptions: options));
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> reloadDropdownOptions() async {
|
Future<void> reloadDropdownOptions() async {
|
||||||
final current = state.valueOrNull;
|
final current = state.valueOrNull;
|
||||||
if (current == null) return;
|
if (current == null) return;
|
||||||
final options = await _loadDropdownOptions();
|
final options = await _loadDropdownOptions(values: current.values);
|
||||||
state = AsyncData(current.copyWith(dropdownOptions: options));
|
state = AsyncData(current.copyWith(dropdownOptions: options));
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> _buildPayload(MasterFormState current) {
|
Map<String, dynamic> _buildPayload(MasterFormState current) {
|
||||||
final payload = <String, dynamic>{};
|
final payload = <String, dynamic>{};
|
||||||
for (final field in _definition.formFields) {
|
for (final field in _definition.formFields) {
|
||||||
|
if (!field.isVisibleInForm(current.values)) continue;
|
||||||
final value = current.values[field.key];
|
final value = current.values[field.key];
|
||||||
if (value == null || value == '') continue;
|
if (value == null || value == '') continue;
|
||||||
|
|
||||||
payload[field.key] = switch (field.type) {
|
payload[field.key] = switch (field.type) {
|
||||||
MasterFieldType.number => num.tryParse(value.toString()) ?? value,
|
MasterFieldType.number => num.tryParse(value.toString()) ?? value,
|
||||||
MasterFieldType.dropdown => int.tryParse(value.toString()) ?? value,
|
MasterFieldType.dropdown => field.staticOptions != null ||
|
||||||
|
field.optionsMasterKey == 'asset_depreciation_methods'
|
||||||
|
? value.toString()
|
||||||
|
: int.tryParse(value.toString()) ?? value,
|
||||||
MasterFieldType.boolean => value == true,
|
MasterFieldType.boolean => value == true,
|
||||||
MasterFieldType.text => value.toString().trim(),
|
MasterFieldType.text => value.toString().trim(),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -119,20 +119,74 @@ class _MasterFormPanelState extends ConsumerState<MasterFormPanel> {
|
|||||||
onChanged: (checked) => notifier.updateValue(field.key, checked),
|
onChanged: (checked) => notifier.updateValue(field.key, checked),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return CheckboxListTile(
|
return InkWell(
|
||||||
contentPadding: EdgeInsets.zero,
|
onTap: () => notifier.updateValue(field.key, value != true),
|
||||||
title: Text(field.label),
|
borderRadius: BorderRadius.circular(8),
|
||||||
value: value == true,
|
child: Padding(
|
||||||
onChanged: (checked) =>
|
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||||
notifier.updateValue(field.key, checked ?? false),
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
child: Checkbox(
|
||||||
|
value: value == true,
|
||||||
|
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
onChanged: (checked) =>
|
||||||
|
notifier.updateValue(field.key, checked ?? false),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(
|
||||||
|
field.label,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
case MasterFieldType.dropdown:
|
case MasterFieldType.dropdown:
|
||||||
|
if (field.readOnly) {
|
||||||
|
final display = field.key == 'gst_rate_id'
|
||||||
|
? (gstRateDisplayFromValues(formState.values) ?? '')
|
||||||
|
: (value?.toString() ?? '');
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
return _wrapField(
|
||||||
|
TextFormField(
|
||||||
|
key: ValueKey(
|
||||||
|
'$_formSessionId-${field.key}-readonly-$display',
|
||||||
|
),
|
||||||
|
initialValue: display.isEmpty ? '' : display,
|
||||||
|
readOnly: true,
|
||||||
|
enableInteractiveSelection: false,
|
||||||
|
style: theme.textTheme.bodyLarge?.copyWith(
|
||||||
|
color: theme.colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
decoration: _inputDecoration(field).copyWith(
|
||||||
|
hintText: display.isEmpty
|
||||||
|
? 'Select HSN code first'
|
||||||
|
: null,
|
||||||
|
filled: true,
|
||||||
|
fillColor: theme.colorScheme.surfaceContainerHighest
|
||||||
|
.withValues(alpha: 0.35),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final List<AppDropdownOption<String>> dropdownOptions;
|
final List<AppDropdownOption<String>> dropdownOptions;
|
||||||
if (field.staticOptions != null) {
|
if (field.staticOptions != null) {
|
||||||
dropdownOptions = stringDropdownOptions(field.staticOptions!);
|
dropdownOptions = stringDropdownOptions(field.staticOptions!);
|
||||||
} else {
|
} else {
|
||||||
var options = formState.dropdownOptions[field.optionsMasterKey] ??
|
final lookupKey = masterFieldDropdownLookupKey(
|
||||||
|
masterId: widget.masterId,
|
||||||
|
field: field,
|
||||||
|
values: formState.values,
|
||||||
|
);
|
||||||
|
var options = formState.dropdownOptions[lookupKey] ??
|
||||||
const <Map<String, dynamic>>[];
|
const <Map<String, dynamic>>[];
|
||||||
final filterField = field.filterByFieldKey;
|
final filterField = field.filterByFieldKey;
|
||||||
if (filterField != null) {
|
if (filterField != null) {
|
||||||
@ -178,7 +232,9 @@ class _MasterFormPanelState extends ConsumerState<MasterFormPanel> {
|
|||||||
if (canQuickAdd) {
|
if (canQuickAdd) {
|
||||||
return MasterQuickAddDropdown<String>(
|
return MasterQuickAddDropdown<String>(
|
||||||
key: ValueKey(
|
key: ValueKey(
|
||||||
'$_formSessionId-${field.key}-${filterField == null ? '' : formState.values[filterField]}',
|
'$_formSessionId-${field.key}-'
|
||||||
|
'${filterField == null ? '' : formState.values[filterField]}-'
|
||||||
|
'${formState.values['is_asset_item']}',
|
||||||
),
|
),
|
||||||
masterId: optionsMasterKey,
|
masterId: optionsMasterKey,
|
||||||
label: _fieldLabel(field),
|
label: _fieldLabel(field),
|
||||||
@ -191,9 +247,19 @@ class _MasterFormPanelState extends ConsumerState<MasterFormPanel> {
|
|||||||
: 'Select ${field.label.toLowerCase()}',
|
: 'Select ${field.label.toLowerCase()}',
|
||||||
searchHint: 'Search ${field.label.toLowerCase()}...',
|
searchHint: 'Search ${field.label.toLowerCase()}...',
|
||||||
enabled: parentSelected,
|
enabled: parentSelected,
|
||||||
initialValues: filterField == null
|
initialValues: () {
|
||||||
? null
|
final values = <String, dynamic>{};
|
||||||
: {filterField: formState.values[filterField]},
|
final params = masterFieldOptionsQuery(
|
||||||
|
masterId: widget.masterId,
|
||||||
|
field: field,
|
||||||
|
values: formState.values,
|
||||||
|
);
|
||||||
|
if (params != null) values.addAll(params);
|
||||||
|
if (filterField != null) {
|
||||||
|
values[filterField] = formState.values[filterField];
|
||||||
|
}
|
||||||
|
return values.isEmpty ? null : values;
|
||||||
|
}(),
|
||||||
refreshLookups: () {
|
refreshLookups: () {
|
||||||
ref
|
ref
|
||||||
.read(masterFormProvider(_args).notifier)
|
.read(masterFormProvider(_args).notifier)
|
||||||
@ -323,8 +389,10 @@ class _MasterFormPanelState extends ConsumerState<MasterFormPanel> {
|
|||||||
MasterFormState formState,
|
MasterFormState formState,
|
||||||
) {
|
) {
|
||||||
final def = _definition;
|
final def = _definition;
|
||||||
final regularFields =
|
final regularFields = def.formFields
|
||||||
def.formFields.where((field) => field.key != 'is_active').toList();
|
.where((field) => field.key != 'is_active')
|
||||||
|
.where((field) => field.isVisibleInForm(formState.values))
|
||||||
|
.toList();
|
||||||
MasterFieldDef? activeField;
|
MasterFieldDef? activeField;
|
||||||
for (final field in def.formFields) {
|
for (final field in def.formFields) {
|
||||||
if (field.key == 'is_active') {
|
if (field.key == 'is_active') {
|
||||||
@ -339,8 +407,9 @@ class _MasterFormPanelState extends ConsumerState<MasterFormPanel> {
|
|||||||
while (i < regularFields.length) {
|
while (i < regularFields.length) {
|
||||||
final left = regularFields[i];
|
final left = regularFields[i];
|
||||||
|
|
||||||
// Multiline fields (e.g. HSN Description) always take a full row.
|
// Multiline / Asset Item take a full row.
|
||||||
if (left.multiline) {
|
final fullWidth = left.multiline || left.key == 'is_asset_item';
|
||||||
|
if (fullWidth) {
|
||||||
widgets.add(
|
widgets.add(
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 12),
|
padding: const EdgeInsets.only(bottom: 12),
|
||||||
@ -354,8 +423,9 @@ class _MasterFormPanelState extends ConsumerState<MasterFormPanel> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final hasRight =
|
final hasRight = i + 1 < regularFields.length &&
|
||||||
i + 1 < regularFields.length && !regularFields[i + 1].multiline;
|
!regularFields[i + 1].multiline &&
|
||||||
|
regularFields[i + 1].key != 'is_asset_item';
|
||||||
if (hasRight) {
|
if (hasRight) {
|
||||||
final right = regularFields[i + 1];
|
final right = regularFields[i + 1];
|
||||||
widgets.add(
|
widgets.add(
|
||||||
|
|||||||
@ -124,7 +124,12 @@ class _MasterInlineCreateFormState
|
|||||||
if (field.staticOptions != null) {
|
if (field.staticOptions != null) {
|
||||||
dropdownOptions = stringDropdownOptions(field.staticOptions!);
|
dropdownOptions = stringDropdownOptions(field.staticOptions!);
|
||||||
} else {
|
} else {
|
||||||
var options = formState.dropdownOptions[field.optionsMasterKey] ??
|
final lookupKey = masterFieldDropdownLookupKey(
|
||||||
|
masterId: widget.masterId,
|
||||||
|
field: field,
|
||||||
|
values: formState.values,
|
||||||
|
);
|
||||||
|
var options = formState.dropdownOptions[lookupKey] ??
|
||||||
const <Map<String, dynamic>>[];
|
const <Map<String, dynamic>>[];
|
||||||
final filterField = field.filterByFieldKey;
|
final filterField = field.filterByFieldKey;
|
||||||
if (filterField != null) {
|
if (filterField != null) {
|
||||||
@ -444,6 +449,7 @@ class _MasterInlineCreateFormState
|
|||||||
data: (formState) {
|
data: (formState) {
|
||||||
final fields = def.formFields
|
final fields = def.formFields
|
||||||
.where((f) => f.key != 'is_active')
|
.where((f) => f.key != 'is_active')
|
||||||
|
.where((f) => f.isVisibleInForm(formState.values))
|
||||||
.toList();
|
.toList();
|
||||||
final active = def.formFields
|
final active = def.formFields
|
||||||
.where((f) => f.key == 'is_active')
|
.where((f) => f.key == 'is_active')
|
||||||
|
|||||||
@ -224,7 +224,6 @@ String masterQuickAddNoun(String masterId) {
|
|||||||
'item_subcategories' => 'subcategory',
|
'item_subcategories' => 'subcategory',
|
||||||
'items' => 'item',
|
'items' => 'item',
|
||||||
'hsn_codes' => 'HSN code',
|
'hsn_codes' => 'HSN code',
|
||||||
'brands' => 'brand',
|
|
||||||
'plants' => 'plant',
|
'plants' => 'plant',
|
||||||
'warehouses' => 'warehouse',
|
'warehouses' => 'warehouse',
|
||||||
'designations' => 'designation',
|
'designations' => 'designation',
|
||||||
|
|||||||
@ -35,9 +35,6 @@ class MasterRemoteDataSource {
|
|||||||
Future<List<FilterOptionModel>> listWarehouses() =>
|
Future<List<FilterOptionModel>> listWarehouses() =>
|
||||||
_listOptions(ApiEndpoints.warehouses);
|
_listOptions(ApiEndpoints.warehouses);
|
||||||
|
|
||||||
Future<List<FilterOptionModel>> listBrands() =>
|
|
||||||
_listOptions(ApiEndpoints.brands);
|
|
||||||
|
|
||||||
Future<List<FilterOptionModel>> listUom() => _listOptions(ApiEndpoints.uom);
|
Future<List<FilterOptionModel>> listUom() => _listOptions(ApiEndpoints.uom);
|
||||||
|
|
||||||
Future<List<FilterOptionModel>> listItems() => _listOptions(ApiEndpoints.items);
|
Future<List<FilterOptionModel>> listItems() => _listOptions(ApiEndpoints.items);
|
||||||
@ -48,6 +45,32 @@ class MasterRemoteDataSource {
|
|||||||
Future<List<FilterOptionModel>> listHsnCodes() =>
|
Future<List<FilterOptionModel>> listHsnCodes() =>
|
||||||
_listOptions(ApiEndpoints.hsnCodes);
|
_listOptions(ApiEndpoints.hsnCodes);
|
||||||
|
|
||||||
|
/// HSN options with default `gst_rate_id` for GST autofill on item/PO lines.
|
||||||
|
Future<({List<FilterOptionModel> options, Map<String, int?> gstRateByHsnId})>
|
||||||
|
listHsnCodesWithGstRate() async {
|
||||||
|
final rows = await _listAllMaps(ApiEndpoints.hsnCodes);
|
||||||
|
final options = <FilterOptionModel>[];
|
||||||
|
final gstRateByHsnId = <String, int?>{};
|
||||||
|
|
||||||
|
for (final item in rows) {
|
||||||
|
if (!isActiveOptionRow(item)) continue;
|
||||||
|
final id = item['id']?.toString() ?? '';
|
||||||
|
if (id.isEmpty) continue;
|
||||||
|
|
||||||
|
final nestedGst = item['gst_rate'];
|
||||||
|
gstRateByHsnId[id] = _asInt(
|
||||||
|
item['gst_rate_id'] ??
|
||||||
|
(nestedGst is Map ? nestedGst['id'] : null),
|
||||||
|
);
|
||||||
|
|
||||||
|
final name = _optionLabel(item);
|
||||||
|
if (name.isEmpty) continue;
|
||||||
|
options.add(FilterOptionModel(id: id, name: name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (options: options, gstRateByHsnId: gstRateByHsnId);
|
||||||
|
}
|
||||||
|
|
||||||
/// Active items with default HSN / UOM / GST for PO line autofill.
|
/// Active items with default HSN / UOM / GST for PO line autofill.
|
||||||
Future<
|
Future<
|
||||||
({
|
({
|
||||||
@ -56,10 +79,7 @@ class MasterRemoteDataSource {
|
|||||||
Map<String, int?> uomByItemId,
|
Map<String, int?> uomByItemId,
|
||||||
Map<String, int?> gstRateByItemId,
|
Map<String, int?> gstRateByItemId,
|
||||||
})> listItemsWithHsn() async {
|
})> listItemsWithHsn() async {
|
||||||
final rows = await _listAllMaps(
|
final rows = await _listAllMaps(ApiEndpoints.items);
|
||||||
ApiEndpoints.items,
|
|
||||||
queryParameters: {'is_active': true},
|
|
||||||
);
|
|
||||||
final hsnByItemId = <String, int?>{};
|
final hsnByItemId = <String, int?>{};
|
||||||
final uomByItemId = <String, int?>{};
|
final uomByItemId = <String, int?>{};
|
||||||
final gstRateByItemId = <String, int?>{};
|
final gstRateByItemId = <String, int?>{};
|
||||||
@ -97,10 +117,7 @@ class MasterRemoteDataSource {
|
|||||||
/// GST rate options with numeric `rate_pct` for tax calculations.
|
/// GST rate options with numeric `rate_pct` for tax calculations.
|
||||||
Future<({List<FilterOptionModel> options, Map<String, double> pctById})>
|
Future<({List<FilterOptionModel> options, Map<String, double> pctById})>
|
||||||
listGstRatesWithPct() async {
|
listGstRatesWithPct() async {
|
||||||
final rows = await _listAllMaps(
|
final rows = await _listAllMaps(ApiEndpoints.gstRates);
|
||||||
ApiEndpoints.gstRates,
|
|
||||||
queryParameters: {'is_active': true},
|
|
||||||
);
|
|
||||||
final options = <FilterOptionModel>[];
|
final options = <FilterOptionModel>[];
|
||||||
final pctById = <String, double>{};
|
final pctById = <String, double>{};
|
||||||
|
|
||||||
@ -123,14 +140,29 @@ class MasterRemoteDataSource {
|
|||||||
return (options: options, pctById: pctById);
|
return (options: options, pctById: pctById);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<FilterOptionModel>> listItemCategories() =>
|
Future<List<FilterOptionModel>> listItemCategories({String? categoryType}) async {
|
||||||
_listOptions(ApiEndpoints.itemCategories);
|
final rows = await _listAllMaps(
|
||||||
|
ApiEndpoints.itemCategories,
|
||||||
|
queryParameters: {
|
||||||
|
if (categoryType != null) 'category_type': categoryType,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return rows
|
||||||
|
.where(isActiveOptionRow)
|
||||||
|
.map(
|
||||||
|
(item) => FilterOptionModel(
|
||||||
|
id: item['id']?.toString() ?? '',
|
||||||
|
name: _optionLabel(item),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.where((item) => item.id.isNotEmpty && item.name.isNotEmpty)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<FilterOptionModel>> listItemSubcategories({int? itemCategoryId}) async {
|
Future<List<FilterOptionModel>> listItemSubcategories({int? itemCategoryId}) async {
|
||||||
final rows = await _listAllMaps(
|
final rows = await _listAllMaps(
|
||||||
ApiEndpoints.itemSubcategories,
|
ApiEndpoints.itemSubcategories,
|
||||||
queryParameters: {
|
queryParameters: {
|
||||||
'is_active': true,
|
|
||||||
if (itemCategoryId != null) 'item_category_id': itemCategoryId,
|
if (itemCategoryId != null) 'item_category_id': itemCategoryId,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -153,10 +185,7 @@ class MasterRemoteDataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<List<FilterOptionModel>> _listOptions(String endpoint) async {
|
Future<List<FilterOptionModel>> _listOptions(String endpoint) async {
|
||||||
final rows = await _listAllMaps(
|
final rows = await _listAllMaps(endpoint);
|
||||||
endpoint,
|
|
||||||
queryParameters: {'is_active': true},
|
|
||||||
);
|
|
||||||
return rows
|
return rows
|
||||||
.where(isActiveOptionRow)
|
.where(isActiveOptionRow)
|
||||||
.map(
|
.map(
|
||||||
@ -169,33 +198,23 @@ class MasterRemoteDataSource {
|
|||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads every page of a masters list (API default page size = 20).
|
/// Form-dropdown loader: uses `dropdown_call=true` (all active, no pagination).
|
||||||
Future<List<Map<String, dynamic>>> _listAllMaps(
|
Future<List<Map<String, dynamic>>> _listAllMaps(
|
||||||
String endpoint, {
|
String endpoint, {
|
||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
}) async {
|
}) async {
|
||||||
final all = <Map<String, dynamic>>[];
|
final response = await dio.get(
|
||||||
var page = 1;
|
endpoint,
|
||||||
var totalPages = 1;
|
queryParameters: {
|
||||||
final pageSize = AppConstants.defaultPageSize;
|
'dropdown_call': true,
|
||||||
|
...?queryParameters,
|
||||||
while (page <= totalPages) {
|
},
|
||||||
final response = await dio.get(
|
);
|
||||||
endpoint,
|
final parsed = _parsePage(
|
||||||
queryParameters: {
|
response.data,
|
||||||
'page': page,
|
fallbackLimit: AppConstants.defaultPageSize,
|
||||||
'limit': pageSize,
|
);
|
||||||
...?queryParameters,
|
return parsed.items;
|
||||||
},
|
|
||||||
);
|
|
||||||
final parsed = _parsePage(response.data, fallbackLimit: pageSize);
|
|
||||||
all.addAll(parsed.items);
|
|
||||||
totalPages = parsed.totalPages;
|
|
||||||
if (parsed.items.isEmpty) break;
|
|
||||||
page++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return all;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
({List<Map<String, dynamic>> items, int totalPages}) _parsePage(
|
({List<Map<String, dynamic>> items, int totalPages}) _parsePage(
|
||||||
|
|||||||
@ -22,6 +22,33 @@ class PurchaseOrderRemoteDataSource {
|
|||||||
return _parsePaginated(response.data, PurchaseOrderModel.fromJson);
|
return _parsePaginated(response.data, PurchaseOrderModel.fromJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Form-dropdown loader (`dropdown_call=true`). Optional status filter.
|
||||||
|
Future<List<PurchaseOrderModel>> listPurchaseOrderOptions({
|
||||||
|
String? status,
|
||||||
|
}) async {
|
||||||
|
final response = await dio.get(
|
||||||
|
ApiEndpoints.purchaseOrders,
|
||||||
|
queryParameters: {
|
||||||
|
'dropdown_call': true,
|
||||||
|
if (status != null) 'status': status,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
final body = response.data;
|
||||||
|
if (body is! Map) return const [];
|
||||||
|
final raw = body['data'];
|
||||||
|
final list = raw is List
|
||||||
|
? raw
|
||||||
|
: raw is Map
|
||||||
|
? (raw['items'] as List?) ?? const []
|
||||||
|
: const [];
|
||||||
|
return list
|
||||||
|
.whereType<Map>()
|
||||||
|
.map(
|
||||||
|
(item) => PurchaseOrderModel.fromJson(Map<String, dynamic>.from(item)),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
Future<PurchaseOrderModel> getPurchaseOrderById(String id) async {
|
Future<PurchaseOrderModel> getPurchaseOrderById(String id) async {
|
||||||
final response = await dio.get(ApiEndpoints.purchaseOrderById(id));
|
final response = await dio.get(ApiEndpoints.purchaseOrderById(id));
|
||||||
final raw = response.data['data'];
|
final raw = response.data['data'];
|
||||||
@ -204,7 +231,6 @@ class PurchaseOrderRemoteDataSource {
|
|||||||
return {
|
return {
|
||||||
if (query.search != null && query.search!.isNotEmpty) 'search': query.search,
|
if (query.search != null && query.search!.isNotEmpty) 'search': query.search,
|
||||||
if (query.status != null) 'status': query.status,
|
if (query.status != null) 'status': query.status,
|
||||||
if (query.poType != null) 'po_type': query.poType,
|
|
||||||
if (query.vendorId != null) 'vendor_id': query.vendorId,
|
if (query.vendorId != null) 'vendor_id': query.vendorId,
|
||||||
if (query.plantId != null) 'plant_id': query.plantId,
|
if (query.plantId != null) 'plant_id': query.plantId,
|
||||||
if (query.dateFrom != null) 'date_from': query.dateFrom,
|
if (query.dateFrom != null) 'date_from': query.dateFrom,
|
||||||
|
|||||||
@ -32,6 +32,15 @@ class PurchaseOrderRepositoryImpl implements PurchaseOrderRepository {
|
|||||||
return safeApiCall(() => dataSource.getPurchaseOrders(query));
|
return safeApiCall(() => dataSource.getPurchaseOrders(query));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<List<PurchaseOrderModel>>> listPurchaseOrderOptions({
|
||||||
|
String? status,
|
||||||
|
}) {
|
||||||
|
return safeApiCall(
|
||||||
|
() => dataSource.listPurchaseOrderOptions(status: status),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<ExportFileResult>> exportPurchaseOrders(
|
Future<Result<ExportFileResult>> exportPurchaseOrders(
|
||||||
PurchaseOrderListQuery query,
|
PurchaseOrderListQuery query,
|
||||||
|
|||||||
@ -8,6 +8,9 @@ abstract class PurchaseOrderRepository {
|
|||||||
Future<Result<PaginatedResponse<PurchaseOrderModel>>> getPurchaseOrders(
|
Future<Result<PaginatedResponse<PurchaseOrderModel>>> getPurchaseOrders(
|
||||||
PurchaseOrderListQuery query,
|
PurchaseOrderListQuery query,
|
||||||
);
|
);
|
||||||
|
Future<Result<List<PurchaseOrderModel>>> listPurchaseOrderOptions({
|
||||||
|
String? status,
|
||||||
|
});
|
||||||
Future<Result<ExportFileResult>> exportPurchaseOrders(
|
Future<Result<ExportFileResult>> exportPurchaseOrders(
|
||||||
PurchaseOrderListQuery query,
|
PurchaseOrderListQuery query,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import '../../../../core/constants/app_constants.dart';
|
|
||||||
import '../../../../core/utils/active_option.dart';
|
import '../../../../core/utils/active_option.dart';
|
||||||
import '../../../../shared/models/user_management_models.dart';
|
import '../../../../shared/models/user_management_models.dart';
|
||||||
import '../../../../shared/models/vendor_model.dart';
|
|
||||||
import '../../../masters/data/datasources/master_remote_data_source.dart';
|
import '../../../masters/data/datasources/master_remote_data_source.dart';
|
||||||
import '../../../vendors/data/repositories/vendor_repository_impl.dart';
|
import '../../../vendors/data/repositories/vendor_repository_impl.dart';
|
||||||
import '../../../vendors/domain/repositories/vendor_repository.dart';
|
import '../../../vendors/domain/repositories/vendor_repository.dart';
|
||||||
@ -13,7 +11,6 @@ class PurchaseOrderLookups {
|
|||||||
this.vendors = const [],
|
this.vendors = const [],
|
||||||
this.plants = const [],
|
this.plants = const [],
|
||||||
this.warehouses = const [],
|
this.warehouses = const [],
|
||||||
this.brands = const [],
|
|
||||||
this.paymentTerms = const [],
|
this.paymentTerms = const [],
|
||||||
this.deliveryTerms = const [],
|
this.deliveryTerms = const [],
|
||||||
this.items = const [],
|
this.items = const [],
|
||||||
@ -24,12 +21,12 @@ class PurchaseOrderLookups {
|
|||||||
this.gstRates = const [],
|
this.gstRates = const [],
|
||||||
this.gstRatePctById = const {},
|
this.gstRatePctById = const {},
|
||||||
this.hsnCodes = const [],
|
this.hsnCodes = const [],
|
||||||
|
this.hsnGstRateById = const {},
|
||||||
});
|
});
|
||||||
|
|
||||||
final List<FilterOptionModel> vendors;
|
final List<FilterOptionModel> vendors;
|
||||||
final List<FilterOptionModel> plants;
|
final List<FilterOptionModel> plants;
|
||||||
final List<FilterOptionModel> warehouses;
|
final List<FilterOptionModel> warehouses;
|
||||||
final List<FilterOptionModel> brands;
|
|
||||||
final List<FilterOptionModel> paymentTerms;
|
final List<FilterOptionModel> paymentTerms;
|
||||||
final List<FilterOptionModel> deliveryTerms;
|
final List<FilterOptionModel> deliveryTerms;
|
||||||
final List<FilterOptionModel> items;
|
final List<FilterOptionModel> items;
|
||||||
@ -44,6 +41,8 @@ class PurchaseOrderLookups {
|
|||||||
/// GST rate id → `rate_pct` for tax calculations.
|
/// GST rate id → `rate_pct` for tax calculations.
|
||||||
final Map<String, double> gstRatePctById;
|
final Map<String, double> gstRatePctById;
|
||||||
final List<FilterOptionModel> hsnCodes;
|
final List<FilterOptionModel> hsnCodes;
|
||||||
|
/// HSN code id → default `gst_rate_id` from HSN master.
|
||||||
|
final Map<String, int?> hsnGstRateById;
|
||||||
}
|
}
|
||||||
|
|
||||||
final purchaseOrderLookupsProvider =
|
final purchaseOrderLookupsProvider =
|
||||||
@ -55,32 +54,31 @@ final purchaseOrderLookupsProvider =
|
|||||||
|
|
||||||
final itemsWithDefaults = await _safeItemsWithDefaults(master.listItemsWithHsn);
|
final itemsWithDefaults = await _safeItemsWithDefaults(master.listItemsWithHsn);
|
||||||
final gstWithPct = await _safeGstRatesWithPct(master.listGstRatesWithPct);
|
final gstWithPct = await _safeGstRatesWithPct(master.listGstRatesWithPct);
|
||||||
|
final hsnWithGst = await _safeHsnWithGst(master.listHsnCodesWithGstRate);
|
||||||
|
|
||||||
final results = await Future.wait([
|
final results = await Future.wait([
|
||||||
_safeOptions(master.listPlants),
|
_safeOptions(master.listPlants),
|
||||||
_safeOptions(master.listWarehouses),
|
_safeOptions(master.listWarehouses),
|
||||||
_safeOptions(master.listBrands),
|
|
||||||
_safeOptions(master.listPaymentTerms),
|
_safeOptions(master.listPaymentTerms),
|
||||||
_safeOptions(master.listDeliveryTerms),
|
_safeOptions(master.listDeliveryTerms),
|
||||||
_safeOptions(master.listUom),
|
_safeOptions(master.listUom),
|
||||||
_safeOptions(master.listHsnCodes),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return PurchaseOrderLookups(
|
return PurchaseOrderLookups(
|
||||||
vendors: vendors,
|
vendors: vendors,
|
||||||
plants: results[0],
|
plants: results[0],
|
||||||
warehouses: results[1],
|
warehouses: results[1],
|
||||||
brands: results[2],
|
paymentTerms: results[2],
|
||||||
paymentTerms: results[3],
|
deliveryTerms: results[3],
|
||||||
deliveryTerms: results[4],
|
|
||||||
items: itemsWithDefaults.options,
|
items: itemsWithDefaults.options,
|
||||||
itemHsnById: itemsWithDefaults.hsnByItemId,
|
itemHsnById: itemsWithDefaults.hsnByItemId,
|
||||||
itemUomById: itemsWithDefaults.uomByItemId,
|
itemUomById: itemsWithDefaults.uomByItemId,
|
||||||
itemGstRateById: itemsWithDefaults.gstRateByItemId,
|
itemGstRateById: itemsWithDefaults.gstRateByItemId,
|
||||||
uom: results[5],
|
uom: results[4],
|
||||||
gstRates: gstWithPct.options,
|
gstRates: gstWithPct.options,
|
||||||
gstRatePctById: gstWithPct.pctById,
|
gstRatePctById: gstWithPct.pctById,
|
||||||
hsnCodes: results[6],
|
hsnCodes: hsnWithGst.options,
|
||||||
|
hsnGstRateById: hsnWithGst.gstRateByHsnId,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -136,42 +134,36 @@ Future<({List<FilterOptionModel> options, Map<String, double> pctById})>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<({List<FilterOptionModel> options, Map<String, int?> gstRateByHsnId})>
|
||||||
|
_safeHsnWithGst(
|
||||||
|
Future<({List<FilterOptionModel> options, Map<String, int?> gstRateByHsnId})>
|
||||||
|
Function()
|
||||||
|
load,
|
||||||
|
) async {
|
||||||
|
try {
|
||||||
|
return await load();
|
||||||
|
} catch (_) {
|
||||||
|
return (options: <FilterOptionModel>[], gstRateByHsnId: <String, int?>{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<FilterOptionModel>> _fetchActiveVendors(
|
Future<List<FilterOptionModel>> _fetchActiveVendors(
|
||||||
VendorRepository vendorRepo,
|
VendorRepository vendorRepo,
|
||||||
) async {
|
) async {
|
||||||
final vendors = <FilterOptionModel>[];
|
final result = await vendorRepo.listVendorOptions();
|
||||||
var page = 1;
|
if (result.failure != null) {
|
||||||
var totalPages = 1;
|
throw result.failure!;
|
||||||
|
|
||||||
while (page <= totalPages) {
|
|
||||||
final result = await vendorRepo.getVendors(
|
|
||||||
VendorListQuery(
|
|
||||||
page: page,
|
|
||||||
limit: AppConstants.maxPageSize,
|
|
||||||
isActive: true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (result.failure != null) {
|
|
||||||
throw result.failure!;
|
|
||||||
}
|
|
||||||
|
|
||||||
final data = result.data!;
|
|
||||||
vendors.addAll(
|
|
||||||
data.items
|
|
||||||
.where(
|
|
||||||
(vendor) => isActiveVendorOption(
|
|
||||||
isActive: vendor.isActive,
|
|
||||||
status: vendor.status,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.map(
|
|
||||||
(vendor) =>
|
|
||||||
FilterOptionModel(id: vendor.id, name: vendor.vendorName),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
totalPages = data.totalPages;
|
|
||||||
page++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return vendors;
|
return (result.data ?? const [])
|
||||||
|
.where(
|
||||||
|
(vendor) => isActiveVendorOption(
|
||||||
|
isActive: vendor.isActive,
|
||||||
|
status: vendor.status,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.map(
|
||||||
|
(vendor) => FilterOptionModel(id: vendor.id, name: vendor.vendorName),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -112,12 +112,6 @@ class PurchaseOrdersListNotifier
|
|||||||
applyQuery(current.query.copyWith(status: status, page: 1));
|
applyQuery(current.query.copyWith(status: status, page: 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPoTypeFilter(String? poType) {
|
|
||||||
final current = state.valueOrNull;
|
|
||||||
if (current == null) return;
|
|
||||||
applyQuery(current.query.copyWith(poType: poType, page: 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPage(int page) {
|
void setPage(int page) {
|
||||||
final current = state.valueOrNull;
|
final current = state.valueOrNull;
|
||||||
if (current == null) return;
|
if (current == null) return;
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import '../../../../core/errors/failure.dart';
|
|||||||
import '../../../../core/theme/app_colors.dart';
|
import '../../../../core/theme/app_colors.dart';
|
||||||
import '../../../../core/utils/formatters.dart';
|
import '../../../../core/utils/formatters.dart';
|
||||||
import '../../../../shared/models/purchase_order_model.dart';
|
import '../../../../shared/models/purchase_order_model.dart';
|
||||||
|
import '../../../../shared/models/vendor_model.dart';
|
||||||
import '../../../../shared/models/user_management_models.dart';
|
import '../../../../shared/models/user_management_models.dart';
|
||||||
import '../../../../shared/providers/permissions_provider.dart';
|
import '../../../../shared/providers/permissions_provider.dart';
|
||||||
import '../../../../shared/utils/file_download_helper.dart';
|
import '../../../../shared/utils/file_download_helper.dart';
|
||||||
@ -418,7 +419,7 @@ class _DetailHeader extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final subtitleParts = [
|
final subtitleParts = [
|
||||||
poTypeLabel(order.poType),
|
vendorTypeLabel(order.vendorType),
|
||||||
if (order.vendorName?.trim().isNotEmpty == true) order.vendorName!.trim(),
|
if (order.vendorName?.trim().isNotEmpty == true) order.vendorName!.trim(),
|
||||||
if (order.plantName?.trim().isNotEmpty == true) order.plantName!.trim(),
|
if (order.plantName?.trim().isNotEmpty == true) order.plantName!.trim(),
|
||||||
];
|
];
|
||||||
@ -702,7 +703,6 @@ class _OrderDetailsCard extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final brand = _lookupName(lookups?.brands, order.brandId);
|
|
||||||
final paymentTerm =
|
final paymentTerm =
|
||||||
_lookupName(lookups?.paymentTerms, order.paymentTermId);
|
_lookupName(lookups?.paymentTerms, order.paymentTermId);
|
||||||
final deliveryTerm =
|
final deliveryTerm =
|
||||||
@ -733,8 +733,8 @@ class _OrderDetailsCard extends StatelessWidget {
|
|||||||
value: _displayOrDash(order.vendorName),
|
value: _displayOrDash(order.vendorName),
|
||||||
),
|
),
|
||||||
_DetailField(
|
_DetailField(
|
||||||
label: 'PO Type',
|
label: 'Vendor Type',
|
||||||
value: poTypeLabel(order.poType),
|
value: vendorTypeLabel(order.vendorType),
|
||||||
),
|
),
|
||||||
_DetailField(
|
_DetailField(
|
||||||
label: 'Plant',
|
label: 'Plant',
|
||||||
@ -744,7 +744,6 @@ class _OrderDetailsCard extends StatelessWidget {
|
|||||||
label: 'Warehouse',
|
label: 'Warehouse',
|
||||||
value: _displayOrDash(order.warehouseName),
|
value: _displayOrDash(order.warehouseName),
|
||||||
),
|
),
|
||||||
_DetailField(label: 'Brand', value: brand),
|
|
||||||
_DetailField(label: 'Payment Term', value: paymentTerm),
|
_DetailField(label: 'Payment Term', value: paymentTerm),
|
||||||
_DetailField(label: 'Delivery Term', value: deliveryTerm),
|
_DetailField(label: 'Delivery Term', value: deliveryTerm),
|
||||||
];
|
];
|
||||||
@ -1275,7 +1274,7 @@ class _DetailFooter extends StatelessWidget {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'${poTypeLabel(order.poType)} · ${poStatusLabel(order.status)}',
|
'${vendorTypeLabel(order.vendorType)} · ${poStatusLabel(order.status)}',
|
||||||
style: style,
|
style: style,
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
|
|||||||
@ -50,11 +50,9 @@ class _PurchaseOrderFormScreenState extends ConsumerState<PurchaseOrderFormScree
|
|||||||
|
|
||||||
DateTime? _poDate;
|
DateTime? _poDate;
|
||||||
DateTime? _expectedDeliveryDate;
|
DateTime? _expectedDeliveryDate;
|
||||||
String? _poType;
|
|
||||||
int? _vendorId;
|
int? _vendorId;
|
||||||
int? _plantId;
|
int? _plantId;
|
||||||
int? _warehouseId;
|
int? _warehouseId;
|
||||||
int? _brandId;
|
|
||||||
int? _paymentTermId;
|
int? _paymentTermId;
|
||||||
int? _deliveryTermId;
|
int? _deliveryTermId;
|
||||||
final List<PoLineItemDraft> _lines = [];
|
final List<PoLineItemDraft> _lines = [];
|
||||||
@ -99,11 +97,9 @@ class _PurchaseOrderFormScreenState extends ConsumerState<PurchaseOrderFormScree
|
|||||||
setState(() {
|
setState(() {
|
||||||
_poDate = order.poDate ?? DateTime.now();
|
_poDate = order.poDate ?? DateTime.now();
|
||||||
_expectedDeliveryDate = order.expectedDeliveryDate;
|
_expectedDeliveryDate = order.expectedDeliveryDate;
|
||||||
_poType = order.poType;
|
|
||||||
_vendorId = order.vendorId;
|
_vendorId = order.vendorId;
|
||||||
_plantId = order.plantId;
|
_plantId = order.plantId;
|
||||||
_warehouseId = order.warehouseId;
|
_warehouseId = order.warehouseId;
|
||||||
_brandId = order.brandId;
|
|
||||||
_paymentTermId = order.paymentTermId;
|
_paymentTermId = order.paymentTermId;
|
||||||
_deliveryTermId = order.deliveryTermId;
|
_deliveryTermId = order.deliveryTermId;
|
||||||
_discountController.text =
|
_discountController.text =
|
||||||
@ -190,11 +186,9 @@ class _PurchaseOrderFormScreenState extends ConsumerState<PurchaseOrderFormScree
|
|||||||
Map<String, dynamic> _buildPayload() {
|
Map<String, dynamic> _buildPayload() {
|
||||||
return {
|
return {
|
||||||
'po_date': DateFormatter.toApiDate(_poDate ?? DateTime.now()),
|
'po_date': DateFormatter.toApiDate(_poDate ?? DateTime.now()),
|
||||||
'po_type': _poType,
|
|
||||||
'vendor_id': _vendorId,
|
'vendor_id': _vendorId,
|
||||||
'plant_id': _plantId,
|
'plant_id': _plantId,
|
||||||
if (_warehouseId != null) 'warehouse_id': _warehouseId,
|
if (_warehouseId != null) 'warehouse_id': _warehouseId,
|
||||||
if (_brandId != null) 'brand_id': _brandId,
|
|
||||||
if (_paymentTermId != null) 'payment_term_id': _paymentTermId,
|
if (_paymentTermId != null) 'payment_term_id': _paymentTermId,
|
||||||
if (_deliveryTermId != null) 'delivery_term_id': _deliveryTermId,
|
if (_deliveryTermId != null) 'delivery_term_id': _deliveryTermId,
|
||||||
if (_expectedDeliveryDate != null)
|
if (_expectedDeliveryDate != null)
|
||||||
@ -244,7 +238,7 @@ class _PurchaseOrderFormScreenState extends ConsumerState<PurchaseOrderFormScree
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_poType == null || _vendorId == null || _plantId == null) {
|
if (_vendorId == null || _plantId == null) {
|
||||||
showAppToastFromSnackBar(context,
|
showAppToastFromSnackBar(context,
|
||||||
const SnackBar(content: Text('Please complete all required fields')),
|
const SnackBar(content: Text('Please complete all required fields')),
|
||||||
);
|
);
|
||||||
@ -391,23 +385,6 @@ class _PurchaseOrderFormScreenState extends ConsumerState<PurchaseOrderFormScree
|
|||||||
onPicked: (d) => setState(() => _poDate = d),
|
onPicked: (d) => setState(() => _poDate = d),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
AppSearchableDropdown<String>(
|
|
||||||
label: 'PO Type *',
|
|
||||||
value: _poType,
|
|
||||||
hint: 'Select PO type',
|
|
||||||
searchHint: 'Search type...',
|
|
||||||
options: poTypeOptions
|
|
||||||
.map(
|
|
||||||
(e) => AppDropdownOption(
|
|
||||||
value: e.$1,
|
|
||||||
label: e.$2,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
onChanged: (v) => setState(() => _poType = v),
|
|
||||||
validator: (v) =>
|
|
||||||
v == null ? 'PO type is required' : null,
|
|
||||||
),
|
|
||||||
AppSearchableDropdown<int>(
|
AppSearchableDropdown<int>(
|
||||||
label: 'Vendor *',
|
label: 'Vendor *',
|
||||||
value: _dropdownValue(_vendorId, vendorIds),
|
value: _dropdownValue(_vendorId, vendorIds),
|
||||||
@ -432,10 +409,6 @@ class _PurchaseOrderFormScreenState extends ConsumerState<PurchaseOrderFormScree
|
|||||||
validator: (v) =>
|
validator: (v) =>
|
||||||
v == null ? 'Plant is required' : null,
|
v == null ? 'Plant is required' : null,
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
FormRowFour(
|
|
||||||
children: [
|
|
||||||
MasterQuickAddDropdown<int?>(
|
MasterQuickAddDropdown<int?>(
|
||||||
masterId: 'warehouses',
|
masterId: 'warehouses',
|
||||||
label: 'Warehouse',
|
label: 'Warehouse',
|
||||||
@ -449,18 +422,10 @@ class _PurchaseOrderFormScreenState extends ConsumerState<PurchaseOrderFormScree
|
|||||||
onChanged: (v) =>
|
onChanged: (v) =>
|
||||||
setState(() => _warehouseId = v),
|
setState(() => _warehouseId = v),
|
||||||
),
|
),
|
||||||
MasterQuickAddDropdown<int?>(
|
],
|
||||||
masterId: 'brands',
|
),
|
||||||
label: 'Brand',
|
FormRowFour(
|
||||||
value: _brandId,
|
children: [
|
||||||
hint: 'Select brand',
|
|
||||||
searchHint: 'Search brand...',
|
|
||||||
options: _nullableIntOptions(lookups.brands),
|
|
||||||
refreshLookups: () =>
|
|
||||||
ref.invalidate(purchaseOrderLookupsProvider),
|
|
||||||
parseCreatedId: int.tryParse,
|
|
||||||
onChanged: (v) => setState(() => _brandId = v),
|
|
||||||
),
|
|
||||||
MasterQuickAddDropdown<int?>(
|
MasterQuickAddDropdown<int?>(
|
||||||
masterId: 'payment_terms',
|
masterId: 'payment_terms',
|
||||||
label: 'Payment Term',
|
label: 'Payment Term',
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import '../../../../core/errors/failure.dart';
|
|||||||
import '../../../../core/utils/formatters.dart';
|
import '../../../../core/utils/formatters.dart';
|
||||||
import '../../../../core/utils/responsive_utils.dart';
|
import '../../../../core/utils/responsive_utils.dart';
|
||||||
import '../../../../shared/models/purchase_order_model.dart';
|
import '../../../../shared/models/purchase_order_model.dart';
|
||||||
|
import '../../../../shared/models/vendor_model.dart';
|
||||||
import '../../../../shared/providers/permissions_provider.dart';
|
import '../../../../shared/providers/permissions_provider.dart';
|
||||||
import '../../../../shared/widgets/app_card.dart';
|
import '../../../../shared/widgets/app_card.dart';
|
||||||
import '../../../../shared/widgets/app_confirmation_dialog.dart';
|
import '../../../../shared/widgets/app_confirmation_dialog.dart';
|
||||||
@ -114,8 +115,6 @@ class _PurchaseOrderListScreenState extends ConsumerState<PurchaseOrderListScree
|
|||||||
onSearch: ref.read(purchaseOrdersListProvider.notifier).setSearch,
|
onSearch: ref.read(purchaseOrdersListProvider.notifier).setSearch,
|
||||||
onStatusChanged:
|
onStatusChanged:
|
||||||
ref.read(purchaseOrdersListProvider.notifier).setStatusFilter,
|
ref.read(purchaseOrdersListProvider.notifier).setStatusFilter,
|
||||||
onPoTypeChanged:
|
|
||||||
ref.read(purchaseOrdersListProvider.notifier).setPoTypeFilter,
|
|
||||||
),
|
),
|
||||||
footer: AppPagination(
|
footer: AppPagination(
|
||||||
currentPage: state.query.page,
|
currentPage: state.query.page,
|
||||||
@ -273,7 +272,6 @@ class _FiltersBar extends StatelessWidget {
|
|||||||
required this.statusOptions,
|
required this.statusOptions,
|
||||||
required this.onSearch,
|
required this.onSearch,
|
||||||
required this.onStatusChanged,
|
required this.onStatusChanged,
|
||||||
required this.onPoTypeChanged,
|
|
||||||
this.showExport = false,
|
this.showExport = false,
|
||||||
this.isExporting = false,
|
this.isExporting = false,
|
||||||
this.onExport,
|
this.onExport,
|
||||||
@ -284,7 +282,6 @@ class _FiltersBar extends StatelessWidget {
|
|||||||
final List<AppDropdownOption<String?>> statusOptions;
|
final List<AppDropdownOption<String?>> statusOptions;
|
||||||
final ValueChanged<String> onSearch;
|
final ValueChanged<String> onSearch;
|
||||||
final ValueChanged<String?> onStatusChanged;
|
final ValueChanged<String?> onStatusChanged;
|
||||||
final ValueChanged<String?> onPoTypeChanged;
|
|
||||||
final bool showExport;
|
final bool showExport;
|
||||||
final bool isExporting;
|
final bool isExporting;
|
||||||
final VoidCallback? onExport;
|
final VoidCallback? onExport;
|
||||||
@ -306,19 +303,6 @@ class _FiltersBar extends StatelessWidget {
|
|||||||
options: statusOptions,
|
options: statusOptions,
|
||||||
onChanged: onStatusChanged,
|
onChanged: onStatusChanged,
|
||||||
),
|
),
|
||||||
AppSearchableDropdown<String?>(
|
|
||||||
label: 'PO Type',
|
|
||||||
value: query.poType,
|
|
||||||
searchHint: 'Search type...',
|
|
||||||
isDense: true,
|
|
||||||
options: [
|
|
||||||
const AppDropdownOption(value: null, label: 'All Types'),
|
|
||||||
...poTypeOptions.map(
|
|
||||||
(e) => AppDropdownOption(value: e.$1, label: e.$2),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
onChanged: onPoTypeChanged,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
return AppResponsiveFilterBar(
|
return AppResponsiveFilterBar(
|
||||||
@ -456,7 +440,7 @@ class _PoCardList extends StatelessWidget {
|
|||||||
child: ListTile(
|
child: ListTile(
|
||||||
title: Text(order.poNo ?? 'PO #${order.id}'),
|
title: Text(order.poNo ?? 'PO #${order.id}'),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'${order.vendorName ?? '—'} · ${poTypeLabel(order.poType)}',
|
'${order.vendorName ?? '—'} · ${vendorTypeLabel(order.vendorType)}',
|
||||||
),
|
),
|
||||||
trailing: PoStatusChip(status: order.status, compact: true),
|
trailing: PoStatusChip(status: order.status, compact: true),
|
||||||
onTap: () => onView(order),
|
onTap: () => onView(order),
|
||||||
|
|||||||
@ -394,6 +394,18 @@ class _LineItemCardState extends ConsumerState<_LineItemCard> {
|
|||||||
ref.read(purchaseOrderLookupsProvider).valueOrNull?.itemHsnById ??
|
ref.read(purchaseOrderLookupsProvider).valueOrNull?.itemHsnById ??
|
||||||
widget.itemHsnById;
|
widget.itemHsnById;
|
||||||
|
|
||||||
|
Map<String, int?> get _hsnGstRateById =>
|
||||||
|
ref.read(purchaseOrderLookupsProvider).valueOrNull?.hsnGstRateById ??
|
||||||
|
const {};
|
||||||
|
|
||||||
|
void _applyGstFromHsn(int? hsnId) {
|
||||||
|
if (hsnId == null) return;
|
||||||
|
final gst = _hsnGstRateById[hsnId.toString()];
|
||||||
|
if (gst != null) {
|
||||||
|
widget.line.gstRateId = gst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool _fillMissingItemDefaults() {
|
bool _fillMissingItemDefaults() {
|
||||||
final itemId = widget.line.itemId;
|
final itemId = widget.line.itemId;
|
||||||
if (itemId == null) return false;
|
if (itemId == null) return false;
|
||||||
@ -415,6 +427,10 @@ class _LineItemCardState extends ConsumerState<_LineItemCard> {
|
|||||||
widget.line.hsnCodeId = defaultHsn;
|
widget.line.hsnCodeId = defaultHsn;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
if (widget.line.gstRateId == null && widget.line.hsnCodeId != null) {
|
||||||
|
_applyGstFromHsn(widget.line.hsnCodeId);
|
||||||
|
if (widget.line.gstRateId != null) changed = true;
|
||||||
|
}
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,6 +450,9 @@ class _LineItemCardState extends ConsumerState<_LineItemCard> {
|
|||||||
final defaultHsn = _itemHsnById[key];
|
final defaultHsn = _itemHsnById[key];
|
||||||
if (defaultHsn != null) {
|
if (defaultHsn != null) {
|
||||||
widget.line.hsnCodeId = defaultHsn;
|
widget.line.hsnCodeId = defaultHsn;
|
||||||
|
if (widget.line.gstRateId == null) {
|
||||||
|
_applyGstFromHsn(defaultHsn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import '../../../../core/constants/app_constants.dart';
|
|
||||||
import '../../../../core/utils/active_option.dart';
|
import '../../../../core/utils/active_option.dart';
|
||||||
import '../../../../shared/models/user_management_models.dart';
|
import '../../../../shared/models/user_management_models.dart';
|
||||||
import '../../../masters/data/datasources/master_remote_data_source.dart';
|
import '../../../masters/data/datasources/master_remote_data_source.dart';
|
||||||
import '../../../roles/data/repositories/role_repository_impl.dart';
|
import '../../../roles/data/repositories/role_repository_impl.dart';
|
||||||
|
import '../../../users/data/repositories/user_repository_impl.dart';
|
||||||
import '../../../users/presentation/providers/users_provider.dart';
|
import '../../../users/presentation/providers/users_provider.dart';
|
||||||
|
|
||||||
class AddUserFormState {
|
class AddUserFormState {
|
||||||
@ -60,7 +60,7 @@ class AddUserFormNotifier extends FamilyAsyncNotifier<AddUserFormState, String?>
|
|||||||
Future<AddUserFormState> build(String? userId) async {
|
Future<AddUserFormState> build(String? userId) async {
|
||||||
final masterRemote = ref.read(masterRemoteDataSourceProvider);
|
final masterRemote = ref.read(masterRemoteDataSourceProvider);
|
||||||
final roleRepository = ref.read(roleRepositoryProvider);
|
final roleRepository = ref.read(roleRepositoryProvider);
|
||||||
final getUsers = ref.read(getUsersUseCaseProvider);
|
final userRepository = ref.read(userRepositoryProvider);
|
||||||
|
|
||||||
final rolesResult = await roleRepository.listRoleOptions();
|
final rolesResult = await roleRepository.listRoleOptions();
|
||||||
if (rolesResult.failure != null) throw rolesResult.failure!;
|
if (rolesResult.failure != null) throw rolesResult.failure!;
|
||||||
@ -69,16 +69,10 @@ class AddUserFormNotifier extends FamilyAsyncNotifier<AddUserFormState, String?>
|
|||||||
final plants = await masterRemote.listPlants();
|
final plants = await masterRemote.listPlants();
|
||||||
final designations = await masterRemote.listDesignations();
|
final designations = await masterRemote.listDesignations();
|
||||||
|
|
||||||
final usersResult = await getUsers(
|
final usersResult = await userRepository.listUserOptions();
|
||||||
const UserListQuery(
|
|
||||||
limit: AppConstants.maxPageSize,
|
|
||||||
status: 'active',
|
|
||||||
isActive: true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (usersResult.failure != null) throw usersResult.failure!;
|
if (usersResult.failure != null) throw usersResult.failure!;
|
||||||
|
|
||||||
final managers = usersResult.data!.items
|
final managers = (usersResult.data ?? const [])
|
||||||
.where(
|
.where(
|
||||||
(user) =>
|
(user) =>
|
||||||
isReportingManagerRole(user.roleName) &&
|
isReportingManagerRole(user.roleName) &&
|
||||||
|
|||||||
@ -37,9 +37,7 @@ class RoleRemoteDataSource {
|
|||||||
final response = await dio.get(
|
final response = await dio.get(
|
||||||
ApiEndpoints.roles,
|
ApiEndpoints.roles,
|
||||||
queryParameters: {
|
queryParameters: {
|
||||||
'page': 1,
|
'dropdown_call': true,
|
||||||
'limit': 100,
|
|
||||||
'is_active': true,
|
|
||||||
if (search != null && search.isNotEmpty) 'search': search,
|
if (search != null && search.isNotEmpty) 'search': search,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@ -96,6 +96,26 @@ class UserRemoteDataSource {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Form-dropdown loader: all active users (`dropdown_call=true`).
|
||||||
|
Future<List<ManagedUserModel>> listUserOptions() async {
|
||||||
|
final response = await dio.get(
|
||||||
|
ApiEndpoints.users,
|
||||||
|
queryParameters: const {'dropdown_call': true},
|
||||||
|
);
|
||||||
|
final body = response.data;
|
||||||
|
if (body is! Map) return const [];
|
||||||
|
final raw = body['data'];
|
||||||
|
final list = raw is List
|
||||||
|
? raw
|
||||||
|
: raw is Map
|
||||||
|
? (raw['items'] as List?) ?? const []
|
||||||
|
: const [];
|
||||||
|
return list
|
||||||
|
.whereType<Map>()
|
||||||
|
.map((item) => ManagedUserModel.fromJson(Map<String, dynamic>.from(item)))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
Future<ManagedUserModel> getUserById(String id) async {
|
Future<ManagedUserModel> getUserById(String id) async {
|
||||||
final response = await dio.get(ApiEndpoints.userById(id));
|
final response = await dio.get(ApiEndpoints.userById(id));
|
||||||
return ManagedUserModel.fromJson(response.data['data'] as Map<String, dynamic>);
|
return ManagedUserModel.fromJson(response.data['data'] as Map<String, dynamic>);
|
||||||
|
|||||||
@ -35,6 +35,10 @@ class UserRepositoryImpl implements UserRepository {
|
|||||||
) =>
|
) =>
|
||||||
safeApiCall(() => remote.getUsers(query));
|
safeApiCall(() => remote.getUsers(query));
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<List<ManagedUserModel>>> listUserOptions() =>
|
||||||
|
safeApiCall(() => remote.listUserOptions());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<ManagedUserModel>> getUserById(String id) =>
|
Future<Result<ManagedUserModel>> getUserById(String id) =>
|
||||||
safeApiCall(() => remote.getUserById(id));
|
safeApiCall(() => remote.getUserById(id));
|
||||||
|
|||||||
@ -7,6 +7,7 @@ abstract class UserRepository {
|
|||||||
Future<Result<UserSummaryModel>> getSummary();
|
Future<Result<UserSummaryModel>> getSummary();
|
||||||
Future<Result<UserFiltersModel>> getFilters();
|
Future<Result<UserFiltersModel>> getFilters();
|
||||||
Future<Result<PaginatedResponse<ManagedUserModel>>> getUsers(UserListQuery query);
|
Future<Result<PaginatedResponse<ManagedUserModel>>> getUsers(UserListQuery query);
|
||||||
|
Future<Result<List<ManagedUserModel>>> listUserOptions();
|
||||||
Future<Result<ManagedUserModel>> getUserById(String id);
|
Future<Result<ManagedUserModel>> getUserById(String id);
|
||||||
Future<Result<ManagedUserModel>> createUser(CreateUserRequest request);
|
Future<Result<ManagedUserModel>> createUser(CreateUserRequest request);
|
||||||
Future<Result<ManagedUserModel>> updateUser(String id, UpdateUserRequest request);
|
Future<Result<ManagedUserModel>> updateUser(String id, UpdateUserRequest request);
|
||||||
|
|||||||
@ -20,6 +20,15 @@ class VendorRemoteDataSource {
|
|||||||
return _parsePaginated(response.data, VendorModel.fromJson);
|
return _parsePaginated(response.data, VendorModel.fromJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Form-dropdown loader: all active vendors (`dropdown_call=true`).
|
||||||
|
Future<List<VendorModel>> listVendorOptions() async {
|
||||||
|
final response = await dio.get(
|
||||||
|
ApiEndpoints.vendors,
|
||||||
|
queryParameters: const {'dropdown_call': true},
|
||||||
|
);
|
||||||
|
return _parseList(response.data, VendorModel.fromJson);
|
||||||
|
}
|
||||||
|
|
||||||
Future<VendorModel> getVendorById(String id) async {
|
Future<VendorModel> getVendorById(String id) async {
|
||||||
final response = await dio.get(ApiEndpoints.vendorById(id));
|
final response = await dio.get(ApiEndpoints.vendorById(id));
|
||||||
return VendorModel.fromJson(response.data['data'] as Map<String, dynamic>);
|
return VendorModel.fromJson(response.data['data'] as Map<String, dynamic>);
|
||||||
|
|||||||
@ -26,6 +26,11 @@ class VendorRepositoryImpl implements VendorRepository {
|
|||||||
return safeApiCall(() => dataSource.getVendors(query));
|
return safeApiCall(() => dataSource.getVendors(query));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<List<VendorModel>>> listVendorOptions() {
|
||||||
|
return safeApiCall(() => dataSource.listVendorOptions());
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<ExportFileResult>> exportVendors(VendorListQuery query) {
|
Future<Result<ExportFileResult>> exportVendors(VendorListQuery query) {
|
||||||
return safeApiCall(() => dataSource.exportVendors(query));
|
return safeApiCall(() => dataSource.exportVendors(query));
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import '../../../../shared/models/vendor_model.dart';
|
|||||||
|
|
||||||
abstract class VendorRepository {
|
abstract class VendorRepository {
|
||||||
Future<Result<PaginatedResponse<VendorModel>>> getVendors(VendorListQuery query);
|
Future<Result<PaginatedResponse<VendorModel>>> getVendors(VendorListQuery query);
|
||||||
|
Future<Result<List<VendorModel>>> listVendorOptions();
|
||||||
Future<Result<ExportFileResult>> exportVendors(VendorListQuery query);
|
Future<Result<ExportFileResult>> exportVendors(VendorListQuery query);
|
||||||
Future<Result<VendorModel>> getVendorById(String id);
|
Future<Result<VendorModel>> getVendorById(String id);
|
||||||
Future<Result<VendorModel>> createVendor(Map<String, dynamic> data);
|
Future<Result<VendorModel>> createVendor(Map<String, dynamic> data);
|
||||||
|
|||||||
@ -117,6 +117,7 @@ class AssetCategoryModel with _$AssetCategoryModel {
|
|||||||
@JsonKey(fromJson: _idFromJson) required String id,
|
@JsonKey(fromJson: _idFromJson) required String id,
|
||||||
required String code,
|
required String code,
|
||||||
required String name,
|
required String name,
|
||||||
|
@JsonKey(name: 'category_type') String? categoryType,
|
||||||
@JsonKey(name: 'code_prefix') String? codePrefix,
|
@JsonKey(name: 'code_prefix') String? codePrefix,
|
||||||
@JsonKey(name: 'default_useful_life_years', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'default_useful_life_years', fromJson: _intFromJsonNullable)
|
||||||
int? defaultUsefulLifeYears,
|
int? defaultUsefulLifeYears,
|
||||||
|
|||||||
@ -25,6 +25,8 @@ mixin _$AssetCategoryModel {
|
|||||||
String get id => throw _privateConstructorUsedError;
|
String get id => throw _privateConstructorUsedError;
|
||||||
String get code => throw _privateConstructorUsedError;
|
String get code => throw _privateConstructorUsedError;
|
||||||
String get name => throw _privateConstructorUsedError;
|
String get name => throw _privateConstructorUsedError;
|
||||||
|
@JsonKey(name: 'category_type')
|
||||||
|
String? get categoryType => throw _privateConstructorUsedError;
|
||||||
@JsonKey(name: 'code_prefix')
|
@JsonKey(name: 'code_prefix')
|
||||||
String? get codePrefix => throw _privateConstructorUsedError;
|
String? get codePrefix => throw _privateConstructorUsedError;
|
||||||
@JsonKey(name: 'default_useful_life_years', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'default_useful_life_years', fromJson: _intFromJsonNullable)
|
||||||
@ -57,6 +59,7 @@ abstract class $AssetCategoryModelCopyWith<$Res> {
|
|||||||
@JsonKey(fromJson: _idFromJson) String id,
|
@JsonKey(fromJson: _idFromJson) String id,
|
||||||
String code,
|
String code,
|
||||||
String name,
|
String name,
|
||||||
|
@JsonKey(name: 'category_type') String? categoryType,
|
||||||
@JsonKey(name: 'code_prefix') String? codePrefix,
|
@JsonKey(name: 'code_prefix') String? codePrefix,
|
||||||
@JsonKey(name: 'default_useful_life_years', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'default_useful_life_years', fromJson: _intFromJsonNullable)
|
||||||
int? defaultUsefulLifeYears,
|
int? defaultUsefulLifeYears,
|
||||||
@ -86,6 +89,7 @@ class _$AssetCategoryModelCopyWithImpl<$Res, $Val extends AssetCategoryModel>
|
|||||||
Object? id = null,
|
Object? id = null,
|
||||||
Object? code = null,
|
Object? code = null,
|
||||||
Object? name = null,
|
Object? name = null,
|
||||||
|
Object? categoryType = freezed,
|
||||||
Object? codePrefix = freezed,
|
Object? codePrefix = freezed,
|
||||||
Object? defaultUsefulLifeYears = freezed,
|
Object? defaultUsefulLifeYears = freezed,
|
||||||
Object? defaultDepreciationMethod = freezed,
|
Object? defaultDepreciationMethod = freezed,
|
||||||
@ -107,6 +111,10 @@ class _$AssetCategoryModelCopyWithImpl<$Res, $Val extends AssetCategoryModel>
|
|||||||
? _value.name
|
? _value.name
|
||||||
: name // ignore: cast_nullable_to_non_nullable
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
as String,
|
as String,
|
||||||
|
categoryType: freezed == categoryType
|
||||||
|
? _value.categoryType
|
||||||
|
: categoryType // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
codePrefix: freezed == codePrefix
|
codePrefix: freezed == codePrefix
|
||||||
? _value.codePrefix
|
? _value.codePrefix
|
||||||
: codePrefix // ignore: cast_nullable_to_non_nullable
|
: codePrefix // ignore: cast_nullable_to_non_nullable
|
||||||
@ -150,6 +158,7 @@ abstract class _$$AssetCategoryModelImplCopyWith<$Res>
|
|||||||
@JsonKey(fromJson: _idFromJson) String id,
|
@JsonKey(fromJson: _idFromJson) String id,
|
||||||
String code,
|
String code,
|
||||||
String name,
|
String name,
|
||||||
|
@JsonKey(name: 'category_type') String? categoryType,
|
||||||
@JsonKey(name: 'code_prefix') String? codePrefix,
|
@JsonKey(name: 'code_prefix') String? codePrefix,
|
||||||
@JsonKey(name: 'default_useful_life_years', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'default_useful_life_years', fromJson: _intFromJsonNullable)
|
||||||
int? defaultUsefulLifeYears,
|
int? defaultUsefulLifeYears,
|
||||||
@ -178,6 +187,7 @@ class __$$AssetCategoryModelImplCopyWithImpl<$Res>
|
|||||||
Object? id = null,
|
Object? id = null,
|
||||||
Object? code = null,
|
Object? code = null,
|
||||||
Object? name = null,
|
Object? name = null,
|
||||||
|
Object? categoryType = freezed,
|
||||||
Object? codePrefix = freezed,
|
Object? codePrefix = freezed,
|
||||||
Object? defaultUsefulLifeYears = freezed,
|
Object? defaultUsefulLifeYears = freezed,
|
||||||
Object? defaultDepreciationMethod = freezed,
|
Object? defaultDepreciationMethod = freezed,
|
||||||
@ -199,6 +209,10 @@ class __$$AssetCategoryModelImplCopyWithImpl<$Res>
|
|||||||
? _value.name
|
? _value.name
|
||||||
: name // ignore: cast_nullable_to_non_nullable
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
as String,
|
as String,
|
||||||
|
categoryType: freezed == categoryType
|
||||||
|
? _value.categoryType
|
||||||
|
: categoryType // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
codePrefix: freezed == codePrefix
|
codePrefix: freezed == codePrefix
|
||||||
? _value.codePrefix
|
? _value.codePrefix
|
||||||
: codePrefix // ignore: cast_nullable_to_non_nullable
|
: codePrefix // ignore: cast_nullable_to_non_nullable
|
||||||
@ -235,6 +249,7 @@ class _$AssetCategoryModelImpl implements _AssetCategoryModel {
|
|||||||
@JsonKey(fromJson: _idFromJson) required this.id,
|
@JsonKey(fromJson: _idFromJson) required this.id,
|
||||||
required this.code,
|
required this.code,
|
||||||
required this.name,
|
required this.name,
|
||||||
|
@JsonKey(name: 'category_type') this.categoryType,
|
||||||
@JsonKey(name: 'code_prefix') this.codePrefix,
|
@JsonKey(name: 'code_prefix') this.codePrefix,
|
||||||
@JsonKey(name: 'default_useful_life_years', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'default_useful_life_years', fromJson: _intFromJsonNullable)
|
||||||
this.defaultUsefulLifeYears,
|
this.defaultUsefulLifeYears,
|
||||||
@ -256,6 +271,9 @@ class _$AssetCategoryModelImpl implements _AssetCategoryModel {
|
|||||||
@override
|
@override
|
||||||
final String name;
|
final String name;
|
||||||
@override
|
@override
|
||||||
|
@JsonKey(name: 'category_type')
|
||||||
|
final String? categoryType;
|
||||||
|
@override
|
||||||
@JsonKey(name: 'code_prefix')
|
@JsonKey(name: 'code_prefix')
|
||||||
final String? codePrefix;
|
final String? codePrefix;
|
||||||
@override
|
@override
|
||||||
@ -274,7 +292,7 @@ class _$AssetCategoryModelImpl implements _AssetCategoryModel {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'AssetCategoryModel(id: $id, code: $code, name: $name, codePrefix: $codePrefix, defaultUsefulLifeYears: $defaultUsefulLifeYears, defaultDepreciationMethod: $defaultDepreciationMethod, isActive: $isActive, createdAt: $createdAt, updatedAt: $updatedAt)';
|
return 'AssetCategoryModel(id: $id, code: $code, name: $name, categoryType: $categoryType, codePrefix: $codePrefix, defaultUsefulLifeYears: $defaultUsefulLifeYears, defaultDepreciationMethod: $defaultDepreciationMethod, isActive: $isActive, createdAt: $createdAt, updatedAt: $updatedAt)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -285,6 +303,8 @@ class _$AssetCategoryModelImpl implements _AssetCategoryModel {
|
|||||||
(identical(other.id, id) || other.id == id) &&
|
(identical(other.id, id) || other.id == id) &&
|
||||||
(identical(other.code, code) || other.code == code) &&
|
(identical(other.code, code) || other.code == code) &&
|
||||||
(identical(other.name, name) || other.name == name) &&
|
(identical(other.name, name) || other.name == name) &&
|
||||||
|
(identical(other.categoryType, categoryType) ||
|
||||||
|
other.categoryType == categoryType) &&
|
||||||
(identical(other.codePrefix, codePrefix) ||
|
(identical(other.codePrefix, codePrefix) ||
|
||||||
other.codePrefix == codePrefix) &&
|
other.codePrefix == codePrefix) &&
|
||||||
(identical(other.defaultUsefulLifeYears, defaultUsefulLifeYears) ||
|
(identical(other.defaultUsefulLifeYears, defaultUsefulLifeYears) ||
|
||||||
@ -309,6 +329,7 @@ class _$AssetCategoryModelImpl implements _AssetCategoryModel {
|
|||||||
id,
|
id,
|
||||||
code,
|
code,
|
||||||
name,
|
name,
|
||||||
|
categoryType,
|
||||||
codePrefix,
|
codePrefix,
|
||||||
defaultUsefulLifeYears,
|
defaultUsefulLifeYears,
|
||||||
defaultDepreciationMethod,
|
defaultDepreciationMethod,
|
||||||
@ -339,6 +360,7 @@ abstract class _AssetCategoryModel implements AssetCategoryModel {
|
|||||||
@JsonKey(fromJson: _idFromJson) required final String id,
|
@JsonKey(fromJson: _idFromJson) required final String id,
|
||||||
required final String code,
|
required final String code,
|
||||||
required final String name,
|
required final String name,
|
||||||
|
@JsonKey(name: 'category_type') final String? categoryType,
|
||||||
@JsonKey(name: 'code_prefix') final String? codePrefix,
|
@JsonKey(name: 'code_prefix') final String? codePrefix,
|
||||||
@JsonKey(name: 'default_useful_life_years', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'default_useful_life_years', fromJson: _intFromJsonNullable)
|
||||||
final int? defaultUsefulLifeYears,
|
final int? defaultUsefulLifeYears,
|
||||||
@ -360,6 +382,9 @@ abstract class _AssetCategoryModel implements AssetCategoryModel {
|
|||||||
@override
|
@override
|
||||||
String get name;
|
String get name;
|
||||||
@override
|
@override
|
||||||
|
@JsonKey(name: 'category_type')
|
||||||
|
String? get categoryType;
|
||||||
|
@override
|
||||||
@JsonKey(name: 'code_prefix')
|
@JsonKey(name: 'code_prefix')
|
||||||
String? get codePrefix;
|
String? get codePrefix;
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -12,6 +12,7 @@ _$AssetCategoryModelImpl _$$AssetCategoryModelImplFromJson(
|
|||||||
id: _idFromJson(json['id']),
|
id: _idFromJson(json['id']),
|
||||||
code: json['code'] as String,
|
code: json['code'] as String,
|
||||||
name: json['name'] as String,
|
name: json['name'] as String,
|
||||||
|
categoryType: json['category_type'] as String?,
|
||||||
codePrefix: json['code_prefix'] as String?,
|
codePrefix: json['code_prefix'] as String?,
|
||||||
defaultUsefulLifeYears: _intFromJsonNullable(
|
defaultUsefulLifeYears: _intFromJsonNullable(
|
||||||
json['default_useful_life_years'],
|
json['default_useful_life_years'],
|
||||||
@ -32,6 +33,7 @@ Map<String, dynamic> _$$AssetCategoryModelImplToJson(
|
|||||||
'id': instance.id,
|
'id': instance.id,
|
||||||
'code': instance.code,
|
'code': instance.code,
|
||||||
'name': instance.name,
|
'name': instance.name,
|
||||||
|
'category_type': instance.categoryType,
|
||||||
'code_prefix': instance.codePrefix,
|
'code_prefix': instance.codePrefix,
|
||||||
'default_useful_life_years': instance.defaultUsefulLifeYears,
|
'default_useful_life_years': instance.defaultUsefulLifeYears,
|
||||||
'default_depreciation_method': instance.defaultDepreciationMethod,
|
'default_depreciation_method': instance.defaultDepreciationMethod,
|
||||||
|
|||||||
@ -38,6 +38,17 @@ Object? _readNestedName(Map<dynamic, dynamic> json, String flatKey, String neste
|
|||||||
Object? _readVendorName(Map<dynamic, dynamic> json, String key) =>
|
Object? _readVendorName(Map<dynamic, dynamic> json, String key) =>
|
||||||
_readNestedName(json, 'vendor_name', 'vendor');
|
_readNestedName(json, 'vendor_name', 'vendor');
|
||||||
|
|
||||||
|
Object? _readVendorType(Map<dynamic, dynamic> json, String key) {
|
||||||
|
final flat = json['vendor_type'];
|
||||||
|
if (flat is String && flat.isNotEmpty) return flat;
|
||||||
|
final nested = json['vendor'];
|
||||||
|
if (nested is Map) {
|
||||||
|
final type = nested['vendor_type'];
|
||||||
|
if (type != null && type.toString().isNotEmpty) return type;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Object? _readPlantName(Map<dynamic, dynamic> json, String key) =>
|
Object? _readPlantName(Map<dynamic, dynamic> json, String key) =>
|
||||||
_readNestedName(json, 'plant_name', 'plant');
|
_readNestedName(json, 'plant_name', 'plant');
|
||||||
|
|
||||||
@ -139,15 +150,14 @@ class PurchaseOrderModel with _$PurchaseOrderModel {
|
|||||||
@JsonKey(fromJson: _idFromJson) required String id,
|
@JsonKey(fromJson: _idFromJson) required String id,
|
||||||
@JsonKey(name: 'po_number', readValue: _readPoNumber) String? poNo,
|
@JsonKey(name: 'po_number', readValue: _readPoNumber) String? poNo,
|
||||||
@JsonKey(name: 'po_date', fromJson: _dateFromJsonNullable) DateTime? poDate,
|
@JsonKey(name: 'po_date', fromJson: _dateFromJsonNullable) DateTime? poDate,
|
||||||
@JsonKey(name: 'po_type') String? poType,
|
|
||||||
@Default('DRAFT') String status,
|
@Default('DRAFT') String status,
|
||||||
@JsonKey(name: 'vendor_id', fromJson: _intFromJsonNullable) int? vendorId,
|
@JsonKey(name: 'vendor_id', fromJson: _intFromJsonNullable) int? vendorId,
|
||||||
@JsonKey(name: 'vendor_name', readValue: _readVendorName) String? vendorName,
|
@JsonKey(name: 'vendor_name', readValue: _readVendorName) String? vendorName,
|
||||||
|
@JsonKey(name: 'vendor_type', readValue: _readVendorType) String? vendorType,
|
||||||
@JsonKey(name: 'plant_id', fromJson: _intFromJsonNullable) int? plantId,
|
@JsonKey(name: 'plant_id', fromJson: _intFromJsonNullable) int? plantId,
|
||||||
@JsonKey(name: 'plant_name', readValue: _readPlantName) String? plantName,
|
@JsonKey(name: 'plant_name', readValue: _readPlantName) String? plantName,
|
||||||
@JsonKey(name: 'warehouse_id', fromJson: _intFromJsonNullable) int? warehouseId,
|
@JsonKey(name: 'warehouse_id', fromJson: _intFromJsonNullable) int? warehouseId,
|
||||||
@JsonKey(name: 'warehouse_name', readValue: _readWarehouseName) String? warehouseName,
|
@JsonKey(name: 'warehouse_name', readValue: _readWarehouseName) String? warehouseName,
|
||||||
@JsonKey(name: 'brand_id', fromJson: _intFromJsonNullable) int? brandId,
|
|
||||||
@JsonKey(name: 'payment_term_id', fromJson: _intFromJsonNullable) int? paymentTermId,
|
@JsonKey(name: 'payment_term_id', fromJson: _intFromJsonNullable) int? paymentTermId,
|
||||||
@JsonKey(name: 'delivery_term_id', fromJson: _intFromJsonNullable) int? deliveryTermId,
|
@JsonKey(name: 'delivery_term_id', fromJson: _intFromJsonNullable) int? deliveryTermId,
|
||||||
@JsonKey(name: 'expected_delivery_date', fromJson: _dateFromJsonNullable)
|
@JsonKey(name: 'expected_delivery_date', fromJson: _dateFromJsonNullable)
|
||||||
@ -254,7 +264,6 @@ class PurchaseOrderListQuery with _$PurchaseOrderListQuery {
|
|||||||
@Default(20) int limit,
|
@Default(20) int limit,
|
||||||
String? search,
|
String? search,
|
||||||
String? status,
|
String? status,
|
||||||
String? poType,
|
|
||||||
int? vendorId,
|
int? vendorId,
|
||||||
int? plantId,
|
int? plantId,
|
||||||
String? dateFrom,
|
String? dateFrom,
|
||||||
@ -262,14 +271,6 @@ class PurchaseOrderListQuery with _$PurchaseOrderListQuery {
|
|||||||
}) = _PurchaseOrderListQuery;
|
}) = _PurchaseOrderListQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
const poTypeOptions = [
|
|
||||||
('RAW_MATERIAL', 'Raw Material'),
|
|
||||||
('PACKING_MATERIAL', 'Packing Material'),
|
|
||||||
('ASSET_CAPITAL', 'Asset / Capital'),
|
|
||||||
('SERVICE', 'Service'),
|
|
||||||
('GENERAL', 'General'),
|
|
||||||
];
|
|
||||||
|
|
||||||
const poStatusOptions = [
|
const poStatusOptions = [
|
||||||
('DRAFT', 'Draft'),
|
('DRAFT', 'Draft'),
|
||||||
// ('SUBMITTED', 'Submitted'),
|
// ('SUBMITTED', 'Submitted'),
|
||||||
@ -281,15 +282,6 @@ const poStatusOptions = [
|
|||||||
('FULLY_RECEIVED', 'Fully Received'),
|
('FULLY_RECEIVED', 'Fully Received'),
|
||||||
];
|
];
|
||||||
|
|
||||||
String poTypeLabel(String? value) {
|
|
||||||
if (value == null) return '—';
|
|
||||||
return poTypeOptions
|
|
||||||
.where((e) => e.$1 == value)
|
|
||||||
.map((e) => e.$2)
|
|
||||||
.firstOrNull ??
|
|
||||||
value;
|
|
||||||
}
|
|
||||||
|
|
||||||
String poStatusLabel(String? value) {
|
String poStatusLabel(String? value) {
|
||||||
if (value == null) return '—';
|
if (value == null) return '—';
|
||||||
final normalizedKey = value.trim().toUpperCase().replaceAll(' ', '_');
|
final normalizedKey = value.trim().toUpperCase().replaceAll(' ', '_');
|
||||||
|
|||||||
@ -27,13 +27,13 @@ mixin _$PurchaseOrderModel {
|
|||||||
String? get poNo => throw _privateConstructorUsedError;
|
String? get poNo => throw _privateConstructorUsedError;
|
||||||
@JsonKey(name: 'po_date', fromJson: _dateFromJsonNullable)
|
@JsonKey(name: 'po_date', fromJson: _dateFromJsonNullable)
|
||||||
DateTime? get poDate => throw _privateConstructorUsedError;
|
DateTime? get poDate => throw _privateConstructorUsedError;
|
||||||
@JsonKey(name: 'po_type')
|
|
||||||
String? get poType => throw _privateConstructorUsedError;
|
|
||||||
String get status => throw _privateConstructorUsedError;
|
String get status => throw _privateConstructorUsedError;
|
||||||
@JsonKey(name: 'vendor_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'vendor_id', fromJson: _intFromJsonNullable)
|
||||||
int? get vendorId => throw _privateConstructorUsedError;
|
int? get vendorId => throw _privateConstructorUsedError;
|
||||||
@JsonKey(name: 'vendor_name', readValue: _readVendorName)
|
@JsonKey(name: 'vendor_name', readValue: _readVendorName)
|
||||||
String? get vendorName => throw _privateConstructorUsedError;
|
String? get vendorName => throw _privateConstructorUsedError;
|
||||||
|
@JsonKey(name: 'vendor_type', readValue: _readVendorType)
|
||||||
|
String? get vendorType => throw _privateConstructorUsedError;
|
||||||
@JsonKey(name: 'plant_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'plant_id', fromJson: _intFromJsonNullable)
|
||||||
int? get plantId => throw _privateConstructorUsedError;
|
int? get plantId => throw _privateConstructorUsedError;
|
||||||
@JsonKey(name: 'plant_name', readValue: _readPlantName)
|
@JsonKey(name: 'plant_name', readValue: _readPlantName)
|
||||||
@ -42,8 +42,6 @@ mixin _$PurchaseOrderModel {
|
|||||||
int? get warehouseId => throw _privateConstructorUsedError;
|
int? get warehouseId => throw _privateConstructorUsedError;
|
||||||
@JsonKey(name: 'warehouse_name', readValue: _readWarehouseName)
|
@JsonKey(name: 'warehouse_name', readValue: _readWarehouseName)
|
||||||
String? get warehouseName => throw _privateConstructorUsedError;
|
String? get warehouseName => throw _privateConstructorUsedError;
|
||||||
@JsonKey(name: 'brand_id', fromJson: _intFromJsonNullable)
|
|
||||||
int? get brandId => throw _privateConstructorUsedError;
|
|
||||||
@JsonKey(name: 'payment_term_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'payment_term_id', fromJson: _intFromJsonNullable)
|
||||||
int? get paymentTermId => throw _privateConstructorUsedError;
|
int? get paymentTermId => throw _privateConstructorUsedError;
|
||||||
@JsonKey(name: 'delivery_term_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'delivery_term_id', fromJson: _intFromJsonNullable)
|
||||||
@ -94,18 +92,18 @@ abstract class $PurchaseOrderModelCopyWith<$Res> {
|
|||||||
@JsonKey(fromJson: _idFromJson) String id,
|
@JsonKey(fromJson: _idFromJson) String id,
|
||||||
@JsonKey(name: 'po_number', readValue: _readPoNumber) String? poNo,
|
@JsonKey(name: 'po_number', readValue: _readPoNumber) String? poNo,
|
||||||
@JsonKey(name: 'po_date', fromJson: _dateFromJsonNullable) DateTime? poDate,
|
@JsonKey(name: 'po_date', fromJson: _dateFromJsonNullable) DateTime? poDate,
|
||||||
@JsonKey(name: 'po_type') String? poType,
|
|
||||||
String status,
|
String status,
|
||||||
@JsonKey(name: 'vendor_id', fromJson: _intFromJsonNullable) int? vendorId,
|
@JsonKey(name: 'vendor_id', fromJson: _intFromJsonNullable) int? vendorId,
|
||||||
@JsonKey(name: 'vendor_name', readValue: _readVendorName)
|
@JsonKey(name: 'vendor_name', readValue: _readVendorName)
|
||||||
String? vendorName,
|
String? vendorName,
|
||||||
|
@JsonKey(name: 'vendor_type', readValue: _readVendorType)
|
||||||
|
String? vendorType,
|
||||||
@JsonKey(name: 'plant_id', fromJson: _intFromJsonNullable) int? plantId,
|
@JsonKey(name: 'plant_id', fromJson: _intFromJsonNullable) int? plantId,
|
||||||
@JsonKey(name: 'plant_name', readValue: _readPlantName) String? plantName,
|
@JsonKey(name: 'plant_name', readValue: _readPlantName) String? plantName,
|
||||||
@JsonKey(name: 'warehouse_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'warehouse_id', fromJson: _intFromJsonNullable)
|
||||||
int? warehouseId,
|
int? warehouseId,
|
||||||
@JsonKey(name: 'warehouse_name', readValue: _readWarehouseName)
|
@JsonKey(name: 'warehouse_name', readValue: _readWarehouseName)
|
||||||
String? warehouseName,
|
String? warehouseName,
|
||||||
@JsonKey(name: 'brand_id', fromJson: _intFromJsonNullable) int? brandId,
|
|
||||||
@JsonKey(name: 'payment_term_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'payment_term_id', fromJson: _intFromJsonNullable)
|
||||||
int? paymentTermId,
|
int? paymentTermId,
|
||||||
@JsonKey(name: 'delivery_term_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'delivery_term_id', fromJson: _intFromJsonNullable)
|
||||||
@ -152,15 +150,14 @@ class _$PurchaseOrderModelCopyWithImpl<$Res, $Val extends PurchaseOrderModel>
|
|||||||
Object? id = null,
|
Object? id = null,
|
||||||
Object? poNo = freezed,
|
Object? poNo = freezed,
|
||||||
Object? poDate = freezed,
|
Object? poDate = freezed,
|
||||||
Object? poType = freezed,
|
|
||||||
Object? status = null,
|
Object? status = null,
|
||||||
Object? vendorId = freezed,
|
Object? vendorId = freezed,
|
||||||
Object? vendorName = freezed,
|
Object? vendorName = freezed,
|
||||||
|
Object? vendorType = freezed,
|
||||||
Object? plantId = freezed,
|
Object? plantId = freezed,
|
||||||
Object? plantName = freezed,
|
Object? plantName = freezed,
|
||||||
Object? warehouseId = freezed,
|
Object? warehouseId = freezed,
|
||||||
Object? warehouseName = freezed,
|
Object? warehouseName = freezed,
|
||||||
Object? brandId = freezed,
|
|
||||||
Object? paymentTermId = freezed,
|
Object? paymentTermId = freezed,
|
||||||
Object? deliveryTermId = freezed,
|
Object? deliveryTermId = freezed,
|
||||||
Object? expectedDeliveryDate = freezed,
|
Object? expectedDeliveryDate = freezed,
|
||||||
@ -191,10 +188,6 @@ class _$PurchaseOrderModelCopyWithImpl<$Res, $Val extends PurchaseOrderModel>
|
|||||||
? _value.poDate
|
? _value.poDate
|
||||||
: poDate // ignore: cast_nullable_to_non_nullable
|
: poDate // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,
|
as DateTime?,
|
||||||
poType: freezed == poType
|
|
||||||
? _value.poType
|
|
||||||
: poType // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
status: null == status
|
status: null == status
|
||||||
? _value.status
|
? _value.status
|
||||||
: status // ignore: cast_nullable_to_non_nullable
|
: status // ignore: cast_nullable_to_non_nullable
|
||||||
@ -207,6 +200,10 @@ class _$PurchaseOrderModelCopyWithImpl<$Res, $Val extends PurchaseOrderModel>
|
|||||||
? _value.vendorName
|
? _value.vendorName
|
||||||
: vendorName // ignore: cast_nullable_to_non_nullable
|
: vendorName // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,
|
||||||
|
vendorType: freezed == vendorType
|
||||||
|
? _value.vendorType
|
||||||
|
: vendorType // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
plantId: freezed == plantId
|
plantId: freezed == plantId
|
||||||
? _value.plantId
|
? _value.plantId
|
||||||
: plantId // ignore: cast_nullable_to_non_nullable
|
: plantId // ignore: cast_nullable_to_non_nullable
|
||||||
@ -223,10 +220,6 @@ class _$PurchaseOrderModelCopyWithImpl<$Res, $Val extends PurchaseOrderModel>
|
|||||||
? _value.warehouseName
|
? _value.warehouseName
|
||||||
: warehouseName // ignore: cast_nullable_to_non_nullable
|
: warehouseName // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,
|
||||||
brandId: freezed == brandId
|
|
||||||
? _value.brandId
|
|
||||||
: brandId // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int?,
|
|
||||||
paymentTermId: freezed == paymentTermId
|
paymentTermId: freezed == paymentTermId
|
||||||
? _value.paymentTermId
|
? _value.paymentTermId
|
||||||
: paymentTermId // ignore: cast_nullable_to_non_nullable
|
: paymentTermId // ignore: cast_nullable_to_non_nullable
|
||||||
@ -306,18 +299,18 @@ abstract class _$$PurchaseOrderModelImplCopyWith<$Res>
|
|||||||
@JsonKey(fromJson: _idFromJson) String id,
|
@JsonKey(fromJson: _idFromJson) String id,
|
||||||
@JsonKey(name: 'po_number', readValue: _readPoNumber) String? poNo,
|
@JsonKey(name: 'po_number', readValue: _readPoNumber) String? poNo,
|
||||||
@JsonKey(name: 'po_date', fromJson: _dateFromJsonNullable) DateTime? poDate,
|
@JsonKey(name: 'po_date', fromJson: _dateFromJsonNullable) DateTime? poDate,
|
||||||
@JsonKey(name: 'po_type') String? poType,
|
|
||||||
String status,
|
String status,
|
||||||
@JsonKey(name: 'vendor_id', fromJson: _intFromJsonNullable) int? vendorId,
|
@JsonKey(name: 'vendor_id', fromJson: _intFromJsonNullable) int? vendorId,
|
||||||
@JsonKey(name: 'vendor_name', readValue: _readVendorName)
|
@JsonKey(name: 'vendor_name', readValue: _readVendorName)
|
||||||
String? vendorName,
|
String? vendorName,
|
||||||
|
@JsonKey(name: 'vendor_type', readValue: _readVendorType)
|
||||||
|
String? vendorType,
|
||||||
@JsonKey(name: 'plant_id', fromJson: _intFromJsonNullable) int? plantId,
|
@JsonKey(name: 'plant_id', fromJson: _intFromJsonNullable) int? plantId,
|
||||||
@JsonKey(name: 'plant_name', readValue: _readPlantName) String? plantName,
|
@JsonKey(name: 'plant_name', readValue: _readPlantName) String? plantName,
|
||||||
@JsonKey(name: 'warehouse_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'warehouse_id', fromJson: _intFromJsonNullable)
|
||||||
int? warehouseId,
|
int? warehouseId,
|
||||||
@JsonKey(name: 'warehouse_name', readValue: _readWarehouseName)
|
@JsonKey(name: 'warehouse_name', readValue: _readWarehouseName)
|
||||||
String? warehouseName,
|
String? warehouseName,
|
||||||
@JsonKey(name: 'brand_id', fromJson: _intFromJsonNullable) int? brandId,
|
|
||||||
@JsonKey(name: 'payment_term_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'payment_term_id', fromJson: _intFromJsonNullable)
|
||||||
int? paymentTermId,
|
int? paymentTermId,
|
||||||
@JsonKey(name: 'delivery_term_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'delivery_term_id', fromJson: _intFromJsonNullable)
|
||||||
@ -363,15 +356,14 @@ class __$$PurchaseOrderModelImplCopyWithImpl<$Res>
|
|||||||
Object? id = null,
|
Object? id = null,
|
||||||
Object? poNo = freezed,
|
Object? poNo = freezed,
|
||||||
Object? poDate = freezed,
|
Object? poDate = freezed,
|
||||||
Object? poType = freezed,
|
|
||||||
Object? status = null,
|
Object? status = null,
|
||||||
Object? vendorId = freezed,
|
Object? vendorId = freezed,
|
||||||
Object? vendorName = freezed,
|
Object? vendorName = freezed,
|
||||||
|
Object? vendorType = freezed,
|
||||||
Object? plantId = freezed,
|
Object? plantId = freezed,
|
||||||
Object? plantName = freezed,
|
Object? plantName = freezed,
|
||||||
Object? warehouseId = freezed,
|
Object? warehouseId = freezed,
|
||||||
Object? warehouseName = freezed,
|
Object? warehouseName = freezed,
|
||||||
Object? brandId = freezed,
|
|
||||||
Object? paymentTermId = freezed,
|
Object? paymentTermId = freezed,
|
||||||
Object? deliveryTermId = freezed,
|
Object? deliveryTermId = freezed,
|
||||||
Object? expectedDeliveryDate = freezed,
|
Object? expectedDeliveryDate = freezed,
|
||||||
@ -402,10 +394,6 @@ class __$$PurchaseOrderModelImplCopyWithImpl<$Res>
|
|||||||
? _value.poDate
|
? _value.poDate
|
||||||
: poDate // ignore: cast_nullable_to_non_nullable
|
: poDate // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,
|
as DateTime?,
|
||||||
poType: freezed == poType
|
|
||||||
? _value.poType
|
|
||||||
: poType // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
status: null == status
|
status: null == status
|
||||||
? _value.status
|
? _value.status
|
||||||
: status // ignore: cast_nullable_to_non_nullable
|
: status // ignore: cast_nullable_to_non_nullable
|
||||||
@ -418,6 +406,10 @@ class __$$PurchaseOrderModelImplCopyWithImpl<$Res>
|
|||||||
? _value.vendorName
|
? _value.vendorName
|
||||||
: vendorName // ignore: cast_nullable_to_non_nullable
|
: vendorName // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,
|
||||||
|
vendorType: freezed == vendorType
|
||||||
|
? _value.vendorType
|
||||||
|
: vendorType // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
plantId: freezed == plantId
|
plantId: freezed == plantId
|
||||||
? _value.plantId
|
? _value.plantId
|
||||||
: plantId // ignore: cast_nullable_to_non_nullable
|
: plantId // ignore: cast_nullable_to_non_nullable
|
||||||
@ -434,10 +426,6 @@ class __$$PurchaseOrderModelImplCopyWithImpl<$Res>
|
|||||||
? _value.warehouseName
|
? _value.warehouseName
|
||||||
: warehouseName // ignore: cast_nullable_to_non_nullable
|
: warehouseName // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,
|
||||||
brandId: freezed == brandId
|
|
||||||
? _value.brandId
|
|
||||||
: brandId // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int?,
|
|
||||||
paymentTermId: freezed == paymentTermId
|
paymentTermId: freezed == paymentTermId
|
||||||
? _value.paymentTermId
|
? _value.paymentTermId
|
||||||
: paymentTermId // ignore: cast_nullable_to_non_nullable
|
: paymentTermId // ignore: cast_nullable_to_non_nullable
|
||||||
@ -510,17 +498,16 @@ class _$PurchaseOrderModelImpl extends _PurchaseOrderModel {
|
|||||||
@JsonKey(fromJson: _idFromJson) required this.id,
|
@JsonKey(fromJson: _idFromJson) required this.id,
|
||||||
@JsonKey(name: 'po_number', readValue: _readPoNumber) this.poNo,
|
@JsonKey(name: 'po_number', readValue: _readPoNumber) this.poNo,
|
||||||
@JsonKey(name: 'po_date', fromJson: _dateFromJsonNullable) this.poDate,
|
@JsonKey(name: 'po_date', fromJson: _dateFromJsonNullable) this.poDate,
|
||||||
@JsonKey(name: 'po_type') this.poType,
|
|
||||||
this.status = 'DRAFT',
|
this.status = 'DRAFT',
|
||||||
@JsonKey(name: 'vendor_id', fromJson: _intFromJsonNullable) this.vendorId,
|
@JsonKey(name: 'vendor_id', fromJson: _intFromJsonNullable) this.vendorId,
|
||||||
@JsonKey(name: 'vendor_name', readValue: _readVendorName) this.vendorName,
|
@JsonKey(name: 'vendor_name', readValue: _readVendorName) this.vendorName,
|
||||||
|
@JsonKey(name: 'vendor_type', readValue: _readVendorType) this.vendorType,
|
||||||
@JsonKey(name: 'plant_id', fromJson: _intFromJsonNullable) this.plantId,
|
@JsonKey(name: 'plant_id', fromJson: _intFromJsonNullable) this.plantId,
|
||||||
@JsonKey(name: 'plant_name', readValue: _readPlantName) this.plantName,
|
@JsonKey(name: 'plant_name', readValue: _readPlantName) this.plantName,
|
||||||
@JsonKey(name: 'warehouse_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'warehouse_id', fromJson: _intFromJsonNullable)
|
||||||
this.warehouseId,
|
this.warehouseId,
|
||||||
@JsonKey(name: 'warehouse_name', readValue: _readWarehouseName)
|
@JsonKey(name: 'warehouse_name', readValue: _readWarehouseName)
|
||||||
this.warehouseName,
|
this.warehouseName,
|
||||||
@JsonKey(name: 'brand_id', fromJson: _intFromJsonNullable) this.brandId,
|
|
||||||
@JsonKey(name: 'payment_term_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'payment_term_id', fromJson: _intFromJsonNullable)
|
||||||
this.paymentTermId,
|
this.paymentTermId,
|
||||||
@JsonKey(name: 'delivery_term_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'delivery_term_id', fromJson: _intFromJsonNullable)
|
||||||
@ -561,9 +548,6 @@ class _$PurchaseOrderModelImpl extends _PurchaseOrderModel {
|
|||||||
@JsonKey(name: 'po_date', fromJson: _dateFromJsonNullable)
|
@JsonKey(name: 'po_date', fromJson: _dateFromJsonNullable)
|
||||||
final DateTime? poDate;
|
final DateTime? poDate;
|
||||||
@override
|
@override
|
||||||
@JsonKey(name: 'po_type')
|
|
||||||
final String? poType;
|
|
||||||
@override
|
|
||||||
@JsonKey()
|
@JsonKey()
|
||||||
final String status;
|
final String status;
|
||||||
@override
|
@override
|
||||||
@ -573,6 +557,9 @@ class _$PurchaseOrderModelImpl extends _PurchaseOrderModel {
|
|||||||
@JsonKey(name: 'vendor_name', readValue: _readVendorName)
|
@JsonKey(name: 'vendor_name', readValue: _readVendorName)
|
||||||
final String? vendorName;
|
final String? vendorName;
|
||||||
@override
|
@override
|
||||||
|
@JsonKey(name: 'vendor_type', readValue: _readVendorType)
|
||||||
|
final String? vendorType;
|
||||||
|
@override
|
||||||
@JsonKey(name: 'plant_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'plant_id', fromJson: _intFromJsonNullable)
|
||||||
final int? plantId;
|
final int? plantId;
|
||||||
@override
|
@override
|
||||||
@ -585,9 +572,6 @@ class _$PurchaseOrderModelImpl extends _PurchaseOrderModel {
|
|||||||
@JsonKey(name: 'warehouse_name', readValue: _readWarehouseName)
|
@JsonKey(name: 'warehouse_name', readValue: _readWarehouseName)
|
||||||
final String? warehouseName;
|
final String? warehouseName;
|
||||||
@override
|
@override
|
||||||
@JsonKey(name: 'brand_id', fromJson: _intFromJsonNullable)
|
|
||||||
final int? brandId;
|
|
||||||
@override
|
|
||||||
@JsonKey(name: 'payment_term_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'payment_term_id', fromJson: _intFromJsonNullable)
|
||||||
final int? paymentTermId;
|
final int? paymentTermId;
|
||||||
@override
|
@override
|
||||||
@ -639,7 +623,7 @@ class _$PurchaseOrderModelImpl extends _PurchaseOrderModel {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'PurchaseOrderModel(id: $id, poNo: $poNo, poDate: $poDate, poType: $poType, status: $status, vendorId: $vendorId, vendorName: $vendorName, plantId: $plantId, plantName: $plantName, warehouseId: $warehouseId, warehouseName: $warehouseName, brandId: $brandId, paymentTermId: $paymentTermId, deliveryTermId: $deliveryTermId, expectedDeliveryDate: $expectedDeliveryDate, discountAmount: $discountAmount, freightCharges: $freightCharges, otherCharges: $otherCharges, taxableAmount: $taxableAmount, taxAmount: $taxAmount, totalAmount: $totalAmount, termsAndConditions: $termsAndConditions, remarks: $remarks, revisionNo: $revisionNo, createdAt: $createdAt, updatedAt: $updatedAt, items: $items)';
|
return 'PurchaseOrderModel(id: $id, poNo: $poNo, poDate: $poDate, status: $status, vendorId: $vendorId, vendorName: $vendorName, vendorType: $vendorType, plantId: $plantId, plantName: $plantName, warehouseId: $warehouseId, warehouseName: $warehouseName, paymentTermId: $paymentTermId, deliveryTermId: $deliveryTermId, expectedDeliveryDate: $expectedDeliveryDate, discountAmount: $discountAmount, freightCharges: $freightCharges, otherCharges: $otherCharges, taxableAmount: $taxableAmount, taxAmount: $taxAmount, totalAmount: $totalAmount, termsAndConditions: $termsAndConditions, remarks: $remarks, revisionNo: $revisionNo, createdAt: $createdAt, updatedAt: $updatedAt, items: $items)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -650,12 +634,13 @@ class _$PurchaseOrderModelImpl extends _PurchaseOrderModel {
|
|||||||
(identical(other.id, id) || other.id == id) &&
|
(identical(other.id, id) || other.id == id) &&
|
||||||
(identical(other.poNo, poNo) || other.poNo == poNo) &&
|
(identical(other.poNo, poNo) || other.poNo == poNo) &&
|
||||||
(identical(other.poDate, poDate) || other.poDate == poDate) &&
|
(identical(other.poDate, poDate) || other.poDate == poDate) &&
|
||||||
(identical(other.poType, poType) || other.poType == poType) &&
|
|
||||||
(identical(other.status, status) || other.status == status) &&
|
(identical(other.status, status) || other.status == status) &&
|
||||||
(identical(other.vendorId, vendorId) ||
|
(identical(other.vendorId, vendorId) ||
|
||||||
other.vendorId == vendorId) &&
|
other.vendorId == vendorId) &&
|
||||||
(identical(other.vendorName, vendorName) ||
|
(identical(other.vendorName, vendorName) ||
|
||||||
other.vendorName == vendorName) &&
|
other.vendorName == vendorName) &&
|
||||||
|
(identical(other.vendorType, vendorType) ||
|
||||||
|
other.vendorType == vendorType) &&
|
||||||
(identical(other.plantId, plantId) || other.plantId == plantId) &&
|
(identical(other.plantId, plantId) || other.plantId == plantId) &&
|
||||||
(identical(other.plantName, plantName) ||
|
(identical(other.plantName, plantName) ||
|
||||||
other.plantName == plantName) &&
|
other.plantName == plantName) &&
|
||||||
@ -663,7 +648,6 @@ class _$PurchaseOrderModelImpl extends _PurchaseOrderModel {
|
|||||||
other.warehouseId == warehouseId) &&
|
other.warehouseId == warehouseId) &&
|
||||||
(identical(other.warehouseName, warehouseName) ||
|
(identical(other.warehouseName, warehouseName) ||
|
||||||
other.warehouseName == warehouseName) &&
|
other.warehouseName == warehouseName) &&
|
||||||
(identical(other.brandId, brandId) || other.brandId == brandId) &&
|
|
||||||
(identical(other.paymentTermId, paymentTermId) ||
|
(identical(other.paymentTermId, paymentTermId) ||
|
||||||
other.paymentTermId == paymentTermId) &&
|
other.paymentTermId == paymentTermId) &&
|
||||||
(identical(other.deliveryTermId, deliveryTermId) ||
|
(identical(other.deliveryTermId, deliveryTermId) ||
|
||||||
@ -701,15 +685,14 @@ class _$PurchaseOrderModelImpl extends _PurchaseOrderModel {
|
|||||||
id,
|
id,
|
||||||
poNo,
|
poNo,
|
||||||
poDate,
|
poDate,
|
||||||
poType,
|
|
||||||
status,
|
status,
|
||||||
vendorId,
|
vendorId,
|
||||||
vendorName,
|
vendorName,
|
||||||
|
vendorType,
|
||||||
plantId,
|
plantId,
|
||||||
plantName,
|
plantName,
|
||||||
warehouseId,
|
warehouseId,
|
||||||
warehouseName,
|
warehouseName,
|
||||||
brandId,
|
|
||||||
paymentTermId,
|
paymentTermId,
|
||||||
deliveryTermId,
|
deliveryTermId,
|
||||||
expectedDeliveryDate,
|
expectedDeliveryDate,
|
||||||
@ -750,12 +733,13 @@ abstract class _PurchaseOrderModel extends PurchaseOrderModel {
|
|||||||
@JsonKey(name: 'po_number', readValue: _readPoNumber) final String? poNo,
|
@JsonKey(name: 'po_number', readValue: _readPoNumber) final String? poNo,
|
||||||
@JsonKey(name: 'po_date', fromJson: _dateFromJsonNullable)
|
@JsonKey(name: 'po_date', fromJson: _dateFromJsonNullable)
|
||||||
final DateTime? poDate,
|
final DateTime? poDate,
|
||||||
@JsonKey(name: 'po_type') final String? poType,
|
|
||||||
final String status,
|
final String status,
|
||||||
@JsonKey(name: 'vendor_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'vendor_id', fromJson: _intFromJsonNullable)
|
||||||
final int? vendorId,
|
final int? vendorId,
|
||||||
@JsonKey(name: 'vendor_name', readValue: _readVendorName)
|
@JsonKey(name: 'vendor_name', readValue: _readVendorName)
|
||||||
final String? vendorName,
|
final String? vendorName,
|
||||||
|
@JsonKey(name: 'vendor_type', readValue: _readVendorType)
|
||||||
|
final String? vendorType,
|
||||||
@JsonKey(name: 'plant_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'plant_id', fromJson: _intFromJsonNullable)
|
||||||
final int? plantId,
|
final int? plantId,
|
||||||
@JsonKey(name: 'plant_name', readValue: _readPlantName)
|
@JsonKey(name: 'plant_name', readValue: _readPlantName)
|
||||||
@ -764,8 +748,6 @@ abstract class _PurchaseOrderModel extends PurchaseOrderModel {
|
|||||||
final int? warehouseId,
|
final int? warehouseId,
|
||||||
@JsonKey(name: 'warehouse_name', readValue: _readWarehouseName)
|
@JsonKey(name: 'warehouse_name', readValue: _readWarehouseName)
|
||||||
final String? warehouseName,
|
final String? warehouseName,
|
||||||
@JsonKey(name: 'brand_id', fromJson: _intFromJsonNullable)
|
|
||||||
final int? brandId,
|
|
||||||
@JsonKey(name: 'payment_term_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'payment_term_id', fromJson: _intFromJsonNullable)
|
||||||
final int? paymentTermId,
|
final int? paymentTermId,
|
||||||
@JsonKey(name: 'delivery_term_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'delivery_term_id', fromJson: _intFromJsonNullable)
|
||||||
@ -809,9 +791,6 @@ abstract class _PurchaseOrderModel extends PurchaseOrderModel {
|
|||||||
@JsonKey(name: 'po_date', fromJson: _dateFromJsonNullable)
|
@JsonKey(name: 'po_date', fromJson: _dateFromJsonNullable)
|
||||||
DateTime? get poDate;
|
DateTime? get poDate;
|
||||||
@override
|
@override
|
||||||
@JsonKey(name: 'po_type')
|
|
||||||
String? get poType;
|
|
||||||
@override
|
|
||||||
String get status;
|
String get status;
|
||||||
@override
|
@override
|
||||||
@JsonKey(name: 'vendor_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'vendor_id', fromJson: _intFromJsonNullable)
|
||||||
@ -820,6 +799,9 @@ abstract class _PurchaseOrderModel extends PurchaseOrderModel {
|
|||||||
@JsonKey(name: 'vendor_name', readValue: _readVendorName)
|
@JsonKey(name: 'vendor_name', readValue: _readVendorName)
|
||||||
String? get vendorName;
|
String? get vendorName;
|
||||||
@override
|
@override
|
||||||
|
@JsonKey(name: 'vendor_type', readValue: _readVendorType)
|
||||||
|
String? get vendorType;
|
||||||
|
@override
|
||||||
@JsonKey(name: 'plant_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'plant_id', fromJson: _intFromJsonNullable)
|
||||||
int? get plantId;
|
int? get plantId;
|
||||||
@override
|
@override
|
||||||
@ -832,9 +814,6 @@ abstract class _PurchaseOrderModel extends PurchaseOrderModel {
|
|||||||
@JsonKey(name: 'warehouse_name', readValue: _readWarehouseName)
|
@JsonKey(name: 'warehouse_name', readValue: _readWarehouseName)
|
||||||
String? get warehouseName;
|
String? get warehouseName;
|
||||||
@override
|
@override
|
||||||
@JsonKey(name: 'brand_id', fromJson: _intFromJsonNullable)
|
|
||||||
int? get brandId;
|
|
||||||
@override
|
|
||||||
@JsonKey(name: 'payment_term_id', fromJson: _intFromJsonNullable)
|
@JsonKey(name: 'payment_term_id', fromJson: _intFromJsonNullable)
|
||||||
int? get paymentTermId;
|
int? get paymentTermId;
|
||||||
@override
|
@override
|
||||||
@ -1662,7 +1641,6 @@ mixin _$PurchaseOrderListQuery {
|
|||||||
int get limit => throw _privateConstructorUsedError;
|
int get limit => throw _privateConstructorUsedError;
|
||||||
String? get search => throw _privateConstructorUsedError;
|
String? get search => throw _privateConstructorUsedError;
|
||||||
String? get status => throw _privateConstructorUsedError;
|
String? get status => throw _privateConstructorUsedError;
|
||||||
String? get poType => throw _privateConstructorUsedError;
|
|
||||||
int? get vendorId => throw _privateConstructorUsedError;
|
int? get vendorId => throw _privateConstructorUsedError;
|
||||||
int? get plantId => throw _privateConstructorUsedError;
|
int? get plantId => throw _privateConstructorUsedError;
|
||||||
String? get dateFrom => throw _privateConstructorUsedError;
|
String? get dateFrom => throw _privateConstructorUsedError;
|
||||||
@ -1687,7 +1665,6 @@ abstract class $PurchaseOrderListQueryCopyWith<$Res> {
|
|||||||
int limit,
|
int limit,
|
||||||
String? search,
|
String? search,
|
||||||
String? status,
|
String? status,
|
||||||
String? poType,
|
|
||||||
int? vendorId,
|
int? vendorId,
|
||||||
int? plantId,
|
int? plantId,
|
||||||
String? dateFrom,
|
String? dateFrom,
|
||||||
@ -1717,7 +1694,6 @@ class _$PurchaseOrderListQueryCopyWithImpl<
|
|||||||
Object? limit = null,
|
Object? limit = null,
|
||||||
Object? search = freezed,
|
Object? search = freezed,
|
||||||
Object? status = freezed,
|
Object? status = freezed,
|
||||||
Object? poType = freezed,
|
|
||||||
Object? vendorId = freezed,
|
Object? vendorId = freezed,
|
||||||
Object? plantId = freezed,
|
Object? plantId = freezed,
|
||||||
Object? dateFrom = freezed,
|
Object? dateFrom = freezed,
|
||||||
@ -1741,10 +1717,6 @@ class _$PurchaseOrderListQueryCopyWithImpl<
|
|||||||
? _value.status
|
? _value.status
|
||||||
: status // ignore: cast_nullable_to_non_nullable
|
: status // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,
|
||||||
poType: freezed == poType
|
|
||||||
? _value.poType
|
|
||||||
: poType // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
vendorId: freezed == vendorId
|
vendorId: freezed == vendorId
|
||||||
? _value.vendorId
|
? _value.vendorId
|
||||||
: vendorId // ignore: cast_nullable_to_non_nullable
|
: vendorId // ignore: cast_nullable_to_non_nullable
|
||||||
@ -1781,7 +1753,6 @@ abstract class _$$PurchaseOrderListQueryImplCopyWith<$Res>
|
|||||||
int limit,
|
int limit,
|
||||||
String? search,
|
String? search,
|
||||||
String? status,
|
String? status,
|
||||||
String? poType,
|
|
||||||
int? vendorId,
|
int? vendorId,
|
||||||
int? plantId,
|
int? plantId,
|
||||||
String? dateFrom,
|
String? dateFrom,
|
||||||
@ -1808,7 +1779,6 @@ class __$$PurchaseOrderListQueryImplCopyWithImpl<$Res>
|
|||||||
Object? limit = null,
|
Object? limit = null,
|
||||||
Object? search = freezed,
|
Object? search = freezed,
|
||||||
Object? status = freezed,
|
Object? status = freezed,
|
||||||
Object? poType = freezed,
|
|
||||||
Object? vendorId = freezed,
|
Object? vendorId = freezed,
|
||||||
Object? plantId = freezed,
|
Object? plantId = freezed,
|
||||||
Object? dateFrom = freezed,
|
Object? dateFrom = freezed,
|
||||||
@ -1832,10 +1802,6 @@ class __$$PurchaseOrderListQueryImplCopyWithImpl<$Res>
|
|||||||
? _value.status
|
? _value.status
|
||||||
: status // ignore: cast_nullable_to_non_nullable
|
: status // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,
|
||||||
poType: freezed == poType
|
|
||||||
? _value.poType
|
|
||||||
: poType // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
vendorId: freezed == vendorId
|
vendorId: freezed == vendorId
|
||||||
? _value.vendorId
|
? _value.vendorId
|
||||||
: vendorId // ignore: cast_nullable_to_non_nullable
|
: vendorId // ignore: cast_nullable_to_non_nullable
|
||||||
@ -1865,7 +1831,6 @@ class _$PurchaseOrderListQueryImpl implements _PurchaseOrderListQuery {
|
|||||||
this.limit = 20,
|
this.limit = 20,
|
||||||
this.search,
|
this.search,
|
||||||
this.status,
|
this.status,
|
||||||
this.poType,
|
|
||||||
this.vendorId,
|
this.vendorId,
|
||||||
this.plantId,
|
this.plantId,
|
||||||
this.dateFrom,
|
this.dateFrom,
|
||||||
@ -1883,8 +1848,6 @@ class _$PurchaseOrderListQueryImpl implements _PurchaseOrderListQuery {
|
|||||||
@override
|
@override
|
||||||
final String? status;
|
final String? status;
|
||||||
@override
|
@override
|
||||||
final String? poType;
|
|
||||||
@override
|
|
||||||
final int? vendorId;
|
final int? vendorId;
|
||||||
@override
|
@override
|
||||||
final int? plantId;
|
final int? plantId;
|
||||||
@ -1895,7 +1858,7 @@ class _$PurchaseOrderListQueryImpl implements _PurchaseOrderListQuery {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'PurchaseOrderListQuery(page: $page, limit: $limit, search: $search, status: $status, poType: $poType, vendorId: $vendorId, plantId: $plantId, dateFrom: $dateFrom, dateTo: $dateTo)';
|
return 'PurchaseOrderListQuery(page: $page, limit: $limit, search: $search, status: $status, vendorId: $vendorId, plantId: $plantId, dateFrom: $dateFrom, dateTo: $dateTo)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -1907,7 +1870,6 @@ class _$PurchaseOrderListQueryImpl implements _PurchaseOrderListQuery {
|
|||||||
(identical(other.limit, limit) || other.limit == limit) &&
|
(identical(other.limit, limit) || other.limit == limit) &&
|
||||||
(identical(other.search, search) || other.search == search) &&
|
(identical(other.search, search) || other.search == search) &&
|
||||||
(identical(other.status, status) || other.status == status) &&
|
(identical(other.status, status) || other.status == status) &&
|
||||||
(identical(other.poType, poType) || other.poType == poType) &&
|
|
||||||
(identical(other.vendorId, vendorId) ||
|
(identical(other.vendorId, vendorId) ||
|
||||||
other.vendorId == vendorId) &&
|
other.vendorId == vendorId) &&
|
||||||
(identical(other.plantId, plantId) || other.plantId == plantId) &&
|
(identical(other.plantId, plantId) || other.plantId == plantId) &&
|
||||||
@ -1923,7 +1885,6 @@ class _$PurchaseOrderListQueryImpl implements _PurchaseOrderListQuery {
|
|||||||
limit,
|
limit,
|
||||||
search,
|
search,
|
||||||
status,
|
status,
|
||||||
poType,
|
|
||||||
vendorId,
|
vendorId,
|
||||||
plantId,
|
plantId,
|
||||||
dateFrom,
|
dateFrom,
|
||||||
@ -1949,7 +1910,6 @@ abstract class _PurchaseOrderListQuery implements PurchaseOrderListQuery {
|
|||||||
final int limit,
|
final int limit,
|
||||||
final String? search,
|
final String? search,
|
||||||
final String? status,
|
final String? status,
|
||||||
final String? poType,
|
|
||||||
final int? vendorId,
|
final int? vendorId,
|
||||||
final int? plantId,
|
final int? plantId,
|
||||||
final String? dateFrom,
|
final String? dateFrom,
|
||||||
@ -1965,8 +1925,6 @@ abstract class _PurchaseOrderListQuery implements PurchaseOrderListQuery {
|
|||||||
@override
|
@override
|
||||||
String? get status;
|
String? get status;
|
||||||
@override
|
@override
|
||||||
String? get poType;
|
|
||||||
@override
|
|
||||||
int? get vendorId;
|
int? get vendorId;
|
||||||
@override
|
@override
|
||||||
int? get plantId;
|
int? get plantId;
|
||||||
|
|||||||
@ -12,15 +12,14 @@ _$PurchaseOrderModelImpl _$$PurchaseOrderModelImplFromJson(
|
|||||||
id: _idFromJson(json['id']),
|
id: _idFromJson(json['id']),
|
||||||
poNo: _readPoNumber(json, 'po_number') as String?,
|
poNo: _readPoNumber(json, 'po_number') as String?,
|
||||||
poDate: _dateFromJsonNullable(json['po_date']),
|
poDate: _dateFromJsonNullable(json['po_date']),
|
||||||
poType: json['po_type'] as String?,
|
|
||||||
status: json['status'] as String? ?? 'DRAFT',
|
status: json['status'] as String? ?? 'DRAFT',
|
||||||
vendorId: _intFromJsonNullable(json['vendor_id']),
|
vendorId: _intFromJsonNullable(json['vendor_id']),
|
||||||
vendorName: _readVendorName(json, 'vendor_name') as String?,
|
vendorName: _readVendorName(json, 'vendor_name') as String?,
|
||||||
|
vendorType: _readVendorType(json, 'vendor_type') as String?,
|
||||||
plantId: _intFromJsonNullable(json['plant_id']),
|
plantId: _intFromJsonNullable(json['plant_id']),
|
||||||
plantName: _readPlantName(json, 'plant_name') as String?,
|
plantName: _readPlantName(json, 'plant_name') as String?,
|
||||||
warehouseId: _intFromJsonNullable(json['warehouse_id']),
|
warehouseId: _intFromJsonNullable(json['warehouse_id']),
|
||||||
warehouseName: _readWarehouseName(json, 'warehouse_name') as String?,
|
warehouseName: _readWarehouseName(json, 'warehouse_name') as String?,
|
||||||
brandId: _intFromJsonNullable(json['brand_id']),
|
|
||||||
paymentTermId: _intFromJsonNullable(json['payment_term_id']),
|
paymentTermId: _intFromJsonNullable(json['payment_term_id']),
|
||||||
deliveryTermId: _intFromJsonNullable(json['delivery_term_id']),
|
deliveryTermId: _intFromJsonNullable(json['delivery_term_id']),
|
||||||
expectedDeliveryDate: _dateFromJsonNullable(json['expected_delivery_date']),
|
expectedDeliveryDate: _dateFromJsonNullable(json['expected_delivery_date']),
|
||||||
@ -50,15 +49,14 @@ Map<String, dynamic> _$$PurchaseOrderModelImplToJson(
|
|||||||
'id': instance.id,
|
'id': instance.id,
|
||||||
'po_number': instance.poNo,
|
'po_number': instance.poNo,
|
||||||
'po_date': instance.poDate?.toIso8601String(),
|
'po_date': instance.poDate?.toIso8601String(),
|
||||||
'po_type': instance.poType,
|
|
||||||
'status': instance.status,
|
'status': instance.status,
|
||||||
'vendor_id': instance.vendorId,
|
'vendor_id': instance.vendorId,
|
||||||
'vendor_name': instance.vendorName,
|
'vendor_name': instance.vendorName,
|
||||||
|
'vendor_type': instance.vendorType,
|
||||||
'plant_id': instance.plantId,
|
'plant_id': instance.plantId,
|
||||||
'plant_name': instance.plantName,
|
'plant_name': instance.plantName,
|
||||||
'warehouse_id': instance.warehouseId,
|
'warehouse_id': instance.warehouseId,
|
||||||
'warehouse_name': instance.warehouseName,
|
'warehouse_name': instance.warehouseName,
|
||||||
'brand_id': instance.brandId,
|
|
||||||
'payment_term_id': instance.paymentTermId,
|
'payment_term_id': instance.paymentTermId,
|
||||||
'delivery_term_id': instance.deliveryTermId,
|
'delivery_term_id': instance.deliveryTermId,
|
||||||
'expected_delivery_date': instance.expectedDeliveryDate?.toIso8601String(),
|
'expected_delivery_date': instance.expectedDeliveryDate?.toIso8601String(),
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import '../../core/utils/validators.dart';
|
import '../../core/utils/validators.dart';
|
||||||
|
import '../../modules/assets/data/repositories/asset_repository_impl.dart';
|
||||||
import '../../modules/master_data/data/repositories/master_repository_impl.dart';
|
import '../../modules/master_data/data/repositories/master_repository_impl.dart';
|
||||||
import '../../modules/master_data/domain/entities/master_definition.dart';
|
import '../../modules/master_data/domain/entities/master_definition.dart';
|
||||||
import 'app_form_toggle_field.dart';
|
import 'app_form_toggle_field.dart';
|
||||||
@ -77,17 +78,46 @@ class _MasterInlineQuickAddFormState
|
|||||||
|
|
||||||
Future<void> _loadOptions() async {
|
Future<void> _loadOptions() async {
|
||||||
final options = <String, List<Map<String, dynamic>>>{};
|
final options = <String, List<Map<String, dynamic>>>{};
|
||||||
final keys = _definition.formFields
|
final fields = _definition.formFields
|
||||||
.where((f) => f.optionsMasterKey != null && f.staticOptions == null)
|
.where((f) => f.optionsMasterKey != null && f.staticOptions == null);
|
||||||
.map((f) => f.optionsMasterKey!)
|
|
||||||
.toSet();
|
for (final field in fields) {
|
||||||
|
final key = field.optionsMasterKey!;
|
||||||
|
final lookupKey = masterFieldDropdownLookupKey(
|
||||||
|
masterId: widget.masterId,
|
||||||
|
field: field,
|
||||||
|
values: _values,
|
||||||
|
);
|
||||||
|
if (options.containsKey(lookupKey)) continue;
|
||||||
|
|
||||||
|
if (key == 'asset_depreciation_methods') {
|
||||||
|
final result =
|
||||||
|
await ref.read(assetRepositoryProvider).getDepreciationMethods();
|
||||||
|
if (result.failure != null) continue;
|
||||||
|
options[lookupKey] = (result.data ?? const [])
|
||||||
|
.where((option) => option.value.trim().isNotEmpty)
|
||||||
|
.map(
|
||||||
|
(option) => <String, dynamic>{
|
||||||
|
'id': option.value,
|
||||||
|
'name': option.label,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (final key in keys) {
|
|
||||||
final def = masterDefinitionById(key);
|
final def = masterDefinitionById(key);
|
||||||
if (def == null) continue;
|
if (def == null) continue;
|
||||||
final result = await ref.read(masterRepositoryProvider).listOptions(def);
|
final result = await ref.read(masterRepositoryProvider).listOptions(
|
||||||
|
def,
|
||||||
|
queryParameters: masterFieldOptionsQuery(
|
||||||
|
masterId: widget.masterId,
|
||||||
|
field: field,
|
||||||
|
values: _values,
|
||||||
|
),
|
||||||
|
);
|
||||||
if (result.failure == null) {
|
if (result.failure == null) {
|
||||||
options[key] = result.data ?? const [];
|
options[lookupKey] = result.data ?? const [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,9 +128,23 @@ class _MasterInlineQuickAddFormState
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _updateValue(String key, dynamic value) {
|
||||||
|
setState(() {
|
||||||
|
_values[key] = value;
|
||||||
|
if (key == 'category_type') {
|
||||||
|
for (final field in _definition.formFields) {
|
||||||
|
if (field.isVisibleInForm(_values)) continue;
|
||||||
|
_values[field.key] = null;
|
||||||
|
_controllers[field.key]?.text = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, dynamic> _buildPayload() {
|
Map<String, dynamic> _buildPayload() {
|
||||||
final payload = <String, dynamic>{};
|
final payload = <String, dynamic>{};
|
||||||
for (final field in _definition.formFields) {
|
for (final field in _definition.formFields) {
|
||||||
|
if (!field.isVisibleInForm(_values)) continue;
|
||||||
var value = _values[field.key];
|
var value = _values[field.key];
|
||||||
if (field.type == MasterFieldType.text ||
|
if (field.type == MasterFieldType.text ||
|
||||||
field.type == MasterFieldType.number) {
|
field.type == MasterFieldType.number) {
|
||||||
@ -109,7 +153,11 @@ class _MasterInlineQuickAddFormState
|
|||||||
if (value == null || value == '') continue;
|
if (value == null || value == '') continue;
|
||||||
payload[field.key] = switch (field.type) {
|
payload[field.key] = switch (field.type) {
|
||||||
MasterFieldType.number => num.tryParse(value.toString()) ?? value,
|
MasterFieldType.number => num.tryParse(value.toString()) ?? value,
|
||||||
MasterFieldType.dropdown => int.tryParse(value.toString()) ?? value,
|
MasterFieldType.dropdown => field.staticOptions != null
|
||||||
|
? value.toString()
|
||||||
|
: (field.optionsMasterKey == 'asset_depreciation_methods'
|
||||||
|
? value.toString()
|
||||||
|
: int.tryParse(value.toString()) ?? value),
|
||||||
MasterFieldType.boolean => value == true,
|
MasterFieldType.boolean => value == true,
|
||||||
MasterFieldType.text => value.toString().trim(),
|
MasterFieldType.text => value.toString().trim(),
|
||||||
};
|
};
|
||||||
@ -157,8 +205,13 @@ class _MasterInlineQuickAddFormState
|
|||||||
.map((v) => <String, dynamic>{'id': v, 'name': v})
|
.map((v) => <String, dynamic>{'id': v, 'name': v})
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
final lookupKey = masterFieldDropdownLookupKey(
|
||||||
|
masterId: widget.masterId,
|
||||||
|
field: field,
|
||||||
|
values: _values,
|
||||||
|
);
|
||||||
var options =
|
var options =
|
||||||
_dropdownOptions[field.optionsMasterKey] ?? const <Map<String, dynamic>>[];
|
_dropdownOptions[lookupKey] ?? const <Map<String, dynamic>>[];
|
||||||
final filterField = field.filterByFieldKey;
|
final filterField = field.filterByFieldKey;
|
||||||
if (filterField != null) {
|
if (filterField != null) {
|
||||||
final parentId = _values[filterField]?.toString();
|
final parentId = _values[filterField]?.toString();
|
||||||
@ -182,7 +235,7 @@ class _MasterInlineQuickAddFormState
|
|||||||
value: _values[field.key] == true,
|
value: _values[field.key] == true,
|
||||||
onChanged: _submitting
|
onChanged: _submitting
|
||||||
? null
|
? null
|
||||||
: (v) => setState(() => _values[field.key] = v),
|
: (v) => _updateValue(field.key, v),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return CheckboxListTile(
|
return CheckboxListTile(
|
||||||
@ -192,7 +245,7 @@ class _MasterInlineQuickAddFormState
|
|||||||
value: _values[field.key] == true,
|
value: _values[field.key] == true,
|
||||||
onChanged: _submitting
|
onChanged: _submitting
|
||||||
? null
|
? null
|
||||||
: (v) => setState(() => _values[field.key] = v ?? false),
|
: (v) => _updateValue(field.key, v ?? false),
|
||||||
);
|
);
|
||||||
|
|
||||||
case MasterFieldType.dropdown:
|
case MasterFieldType.dropdown:
|
||||||
@ -221,7 +274,7 @@ class _MasterInlineQuickAddFormState
|
|||||||
],
|
],
|
||||||
onChanged: (_submitting || prefilled)
|
onChanged: (_submitting || prefilled)
|
||||||
? null
|
? null
|
||||||
: (v) => setState(() => _values[field.key] = v),
|
: (v) => _updateValue(field.key, v),
|
||||||
validator: field.required
|
validator: field.required
|
||||||
? (v) => v == null ? '${field.label} is required' : null
|
? (v) => v == null ? '${field.label} is required' : null
|
||||||
: null,
|
: null,
|
||||||
@ -252,9 +305,12 @@ class _MasterInlineQuickAddFormState
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final fields = _definition.formFields;
|
final fields = _definition.formFields;
|
||||||
final activeField = fields.where((field) => field.key == 'is_active').firstOrNull;
|
final activeField =
|
||||||
final regularFields =
|
fields.where((field) => field.key == 'is_active').firstOrNull;
|
||||||
fields.where((field) => field.key != 'is_active').toList();
|
final regularFields = fields
|
||||||
|
.where((field) => field.key != 'is_active')
|
||||||
|
.where((field) => field.isVisibleInForm(_values))
|
||||||
|
.toList();
|
||||||
|
|
||||||
return Material(
|
return Material(
|
||||||
color: theme.colorScheme.surfaceContainerHighest.withValues(alpha: 0.45),
|
color: theme.colorScheme.surfaceContainerHighest.withValues(alpha: 0.45),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user