Location api change

This commit is contained in:
Surendiran 2026-07-20 12:12:20 +05:30
parent 4046633340
commit 1d44187942
4 changed files with 87 additions and 20 deletions

View File

@ -62,7 +62,10 @@ class MasterCrudRemoteDataSource {
final items = list final items = list
.whereType<Map<String, dynamic>>() .whereType<Map<String, dynamic>>()
.map((item) => Map<String, dynamic>.from(item)) .map((item) => _sanitizeLocationRow(
definition,
Map<String, dynamic>.from(item),
))
.toList(); .toList();
final pagination = parsePagination( final pagination = parsePagination(
@ -104,7 +107,12 @@ class MasterCrudRemoteDataSource {
return list return list
.whereType<Map>() .whereType<Map>()
.map((item) => Map<String, dynamic>.from(item)) .map(
(item) => _sanitizeLocationRow(
definition,
Map<String, dynamic>.from(item),
),
)
.where(isActiveOptionRow) .where(isActiveOptionRow)
.toList(); .toList();
} }
@ -114,7 +122,7 @@ class MasterCrudRemoteDataSource {
String id, String id,
) async { ) async {
final response = await dio.get('${definition.apiPath}/$id'); final response = await dio.get('${definition.apiPath}/$id');
return _extractData(response.data); return _sanitizeLocationRow(definition, _extractData(response.data));
} }
Future<Map<String, dynamic>> create( Future<Map<String, dynamic>> create(
@ -125,7 +133,7 @@ class MasterCrudRemoteDataSource {
definition.apiPath, definition.apiPath,
data: payload..removeWhere((_, value) => value == null), data: payload..removeWhere((_, value) => value == null),
); );
return _extractData(response.data); return _sanitizeLocationRow(definition, _extractData(response.data));
} }
Future<Map<String, dynamic>> update( Future<Map<String, dynamic>> update(
@ -137,7 +145,7 @@ class MasterCrudRemoteDataSource {
'${definition.apiPath}/$id', '${definition.apiPath}/$id',
data: payload..removeWhere((_, value) => value == null), data: payload..removeWhere((_, value) => value == null),
); );
return _extractData(response.data); return _sanitizeLocationRow(definition, _extractData(response.data));
} }
Future<void> delete(MasterDefinition definition, String id) async { Future<void> delete(MasterDefinition definition, String id) async {
@ -197,4 +205,16 @@ class MasterCrudRemoteDataSource {
if (data is Map<String, dynamic>) return Map<String, dynamic>.from(data); if (data is Map<String, dynamic>) return Map<String, dynamic>.from(data);
return Map<String, dynamic>.from(body); return Map<String, dynamic>.from(body);
} }
/// Locations API no longer nests warehouses under plants.
Map<String, dynamic> _sanitizeLocationRow(
MasterDefinition definition,
Map<String, dynamic> row,
) {
if (definition.id != 'locations') return row;
row.remove('parent_id');
row.remove('plant_id');
row.remove('plant');
return row;
}
} }

View File

@ -34,7 +34,7 @@ class MasterFieldDef {
final bool showInForm; final bool showInForm;
/// When true, shown in the form but not editable (value set by other fields). /// When true, shown in the form but not editable (value set by other fields).
final bool readOnly; 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. `locations` for FKs).
final String? optionsMasterKey; final String? optionsMasterKey;
/// Extra query parameters when loading [optionsMasterKey] options. /// Extra query parameters when loading [optionsMasterKey] options.
final Map<String, dynamic>? optionsQueryParams; final Map<String, dynamic>? optionsQueryParams;
@ -48,7 +48,7 @@ class MasterFieldDef {
/// Show this field only when [visibleWhenFieldKey] equals [visibleWhenValue]. /// Show this field only when [visibleWhenFieldKey] equals [visibleWhenValue].
final String? visibleWhenFieldKey; final String? visibleWhenFieldKey;
final String? visibleWhenValue; final String? visibleWhenValue;
/// Nested object key on list rows for display (e.g. `plant` for `parent_id`). /// Nested object key on list rows for display (e.g. `gst_rate` for `gst_rate_id`).
final String? listNestedKey; final String? listNestedKey;
/// Cache key for dropdown option rows (includes query params when set). /// Cache key for dropdown option rows (includes query params when set).
@ -376,32 +376,51 @@ const masterDefinitions = <MasterDefinition>[
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( MasterFieldDef(
key: 'parent_id', key: 'gstin',
label: 'Parent Plant', label: 'GSTIN',
type: MasterFieldType.dropdown,
showInList: true, showInList: true,
optionsMasterKey: 'locations',
optionsQueryParams: const {'type': 'plant'},
listNestedKey: 'plant',
visibleWhenFieldKey: 'type', visibleWhenFieldKey: 'type',
visibleWhenValue: 'warehouse', visibleWhenValue: 'plant',
required: true, ),
MasterFieldDef(
key: 'city',
label: 'City',
showInList: true,
visibleWhenFieldKey: 'type',
visibleWhenValue: 'plant',
), ),
MasterFieldDef(key: 'gstin', label: 'GSTIN', showInList: true),
MasterFieldDef(key: 'city', label: 'City', showInList: true),
MasterFieldDef( MasterFieldDef(
key: 'state', key: 'state',
label: 'State', label: 'State',
type: MasterFieldType.dropdown, type: MasterFieldType.dropdown,
optionsMasterKey: 'location_states', optionsMasterKey: 'location_states',
showInList: true, showInList: true,
visibleWhenFieldKey: 'type',
visibleWhenValue: 'plant',
),
MasterFieldDef(
key: 'address',
label: 'Address',
multiline: true,
visibleWhenFieldKey: 'type',
visibleWhenValue: 'plant',
),
MasterFieldDef(
key: 'pincode',
label: 'Pincode',
visibleWhenFieldKey: 'type',
visibleWhenValue: 'plant',
),
MasterFieldDef(
key: 'phone',
label: 'Phone',
visibleWhenFieldKey: 'type',
visibleWhenValue: 'plant',
), ),
MasterFieldDef(key: 'address', label: 'Address', multiline: true),
MasterFieldDef(key: 'pincode', label: 'Pincode'),
MasterFieldDef(key: 'phone', label: 'Phone'),
MasterFieldDef( MasterFieldDef(
key: 'location', key: 'location',
label: 'Location Detail', label: 'Location Detail',
showInList: true,
visibleWhenFieldKey: 'type', visibleWhenFieldKey: 'type',
visibleWhenValue: 'warehouse', visibleWhenValue: 'warehouse',
), ),

View File

@ -301,6 +301,8 @@ class MasterFormNotifier extends FamilyAsyncNotifier<MasterFormState, MasterForm
} }
} }
_sanitizeLocationValues(values);
// Load after values so Items category options use is_asset_item. // Load after values so Items category options use is_asset_item.
final dropdownOptions = await _loadDropdownOptions(values: values); final dropdownOptions = await _loadDropdownOptions(values: values);
@ -455,6 +457,14 @@ class MasterFormNotifier extends FamilyAsyncNotifier<MasterFormState, MasterForm
} }
} }
/// Warehouses are no longer nested under plants drop obsolete keys.
void _sanitizeLocationValues(Map<String, dynamic> values) {
if (_definition.id != 'locations') return;
values.remove('parent_id');
values.remove('plant_id');
values.remove('plant');
}
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;
@ -469,6 +479,11 @@ class MasterFormNotifier extends FamilyAsyncNotifier<MasterFormState, MasterForm
_clearHiddenFieldValues(values); _clearHiddenFieldValues(values);
} }
if (key == 'type' && _definition.id == 'locations') {
_clearHiddenFieldValues(values);
_sanitizeLocationValues(values);
}
// Asset Item toggles Items category list between STOCK / ASSET // Asset Item toggles Items category list between STOCK / ASSET
// and hides stock-only fields (min order qty / reorder level). // and hides stock-only fields (min order qty / reorder level).
if (key == 'is_asset_item' && _definition.id == 'items') { if (key == 'is_asset_item' && _definition.id == 'items') {
@ -551,6 +566,14 @@ class MasterFormNotifier extends FamilyAsyncNotifier<MasterFormState, MasterForm
MasterFieldType.text => value.toString().trim(), MasterFieldType.text => value.toString().trim(),
}; };
} }
// Never send plant nesting fields for locations (API breaking change).
if (_definition.id == 'locations') {
payload.remove('parent_id');
payload.remove('plant_id');
payload.remove('plant');
}
return payload; return payload;
} }

View File

@ -72,6 +72,11 @@ class MasterRemoteDataSource {
for (final item in rows) { for (final item in rows) {
if (!isActiveOptionRow(item)) continue; if (!isActiveOptionRow(item)) continue;
// Ignore obsolete plant nesting fields if the API still returns them.
item.remove('parent_id');
item.remove('plant_id');
item.remove('plant');
final id = item['id']?.toString() ?? ''; final id = item['id']?.toString() ?? '';
final name = _optionLabel(item); final name = _optionLabel(item);
if (id.isEmpty || name.isEmpty) continue; if (id.isEmpty || name.isEmpty) continue;