feat: warehouse_and_distribution in killhouse module

This commit is contained in:
2025-12-01 15:25:19 +03:30
parent 6861e873ba
commit c42ee069e6
57 changed files with 11246 additions and 208 deletions

View File

@@ -27,9 +27,14 @@ import 'package:rasadyar_chicken/data/models/response/waiting_arrival/waiting_ar
import 'package:rasadyar_core/core.dart';
abstract class ChickenRemoteDatasource {
Future<List<InventoryModel>?> getInventory({required String token, CancelToken? cancelToken});
Future<KillHouseDistributionInfo?> getKillHouseDistributionInfo({required String token});
Future<List<InventoryModel>?> getInventory({
required String token,
required String role,
CancelToken? cancelToken,
});
Future<KillHouseDistributionInfo?> getKillHouseDistributionInfo({
required String token,
});
Future<BarInformation?> getGeneralBarInformation({
required String token,
@@ -41,7 +46,10 @@ abstract class ChickenRemoteDatasource {
Map<String, dynamic>? queryParameters,
});
Future<void> setSateForArrivals({required String token, required Map<String, dynamic> request});
Future<void> setSateForArrivals({
required String token,
required Map<String, dynamic> request,
});
Future<PaginationModel<ImportedLoadsModel>?> getImportedLoadsModel({
required String token,
@@ -53,9 +61,15 @@ abstract class ChickenRemoteDatasource {
Map<String, dynamic>? queryParameters,
});
Future<void> confirmAllocation({required String token, required Map<String, dynamic> allocation});
Future<void> confirmAllocation({
required String token,
required Map<String, dynamic> allocation,
});
Future<void> denyAllocation({required String token, required String allocationToken});
Future<void> denyAllocation({
required String token,
required String allocationToken,
});
Future<void> confirmAllAllocation({
required String token,
@@ -81,7 +95,10 @@ abstract class ChickenRemoteDatasource {
Map<String, dynamic>? queryParameters,
});
Future<void> updateStewardAllocation({required String token, required ConformAllocation request});
Future<void> updateStewardAllocation({
required String token,
required ConformAllocation request,
});
Future<StewardFreeBarDashboard?> getStewardDashboard({
required String token,
@@ -95,7 +112,8 @@ abstract class ChickenRemoteDatasource {
required String endDate,
});
Future<PaginationModel<StewardFreeBar>?> getStewardPurchasesOutSideOfTheProvince({
Future<PaginationModel<StewardFreeBar>?>
getStewardPurchasesOutSideOfTheProvince({
required String token,
Map<String, dynamic>? queryParameters,
});
@@ -115,8 +133,8 @@ abstract class ChickenRemoteDatasource {
Map<String, dynamic>? queryParameters,
});
Future<PaginationModel<OutProvinceCarcassesBuyer>?> getOutProvinceCarcassesBuyer({
Future<PaginationModel<OutProvinceCarcassesBuyer>?>
getOutProvinceCarcassesBuyer({
required String token,
Map<String, dynamic>? queryParameters,
});
@@ -145,29 +163,42 @@ abstract class ChickenRemoteDatasource {
required StewardFreeSaleBarRequest body,
});
Future<void> deleteOutProvinceStewardFreeBar({
required String token,
required String key
required String key,
});
Future<UserProfile?> getUserProfile({required String token});
Future<void> updateUserProfile({required String token, required UserProfile userProfile});
Future<void> updateUserProfile({
required String token,
required UserProfile userProfile,
});
Future<void> updatePassword({required String token, required ChangePasswordRequestModel model});
Future<void> updatePassword({
required String token,
required ChangePasswordRequestModel model,
});
Future<PaginationModel<SegmentationModel>?> getSegmentation({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> createSegmentation({required String token, required SegmentationModel model});
Future<void> createSegmentation({
required String token,
required SegmentationModel model,
});
Future<void> editSegmentation({required String token, required SegmentationModel model});
Future<void> editSegmentation({
required String token,
required SegmentationModel model,
});
Future<SegmentationModel?> deleteSegmentation({required String token, required String key});
Future<SegmentationModel?> deleteSegmentation({
required String token,
required String key,
});
Future<BroadcastPrice?> getBroadcastPrice({required String token});

View File

@@ -36,21 +36,25 @@ class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource {
@override
Future<List<InventoryModel>?> getInventory({
required String token,
required String role,
CancelToken? cancelToken,
}) async {
var res = await _httpClient.get(
'/roles-products/?role=Steward',
'/roles-products/?role=$role',
headers: {'Authorization': 'Bearer $token'},
fromJsonList: (json) =>
(json).map((item) => InventoryModel.fromJson(item as Map<String, dynamic>)).toList(),
fromJsonList: (json) => (json)
.map((item) => InventoryModel.fromJson(item as Map<String, dynamic>))
.toList(),
);
return res.data;
}
@override
Future<KillHouseDistributionInfo?> getKillHouseDistributionInfo({required String token}) async {
Future<KillHouseDistributionInfo?> getKillHouseDistributionInfo({
required String token,
}) async {
var res = await _httpClient.get(
'/kill-house-distribution-info/?role=Steward',
headers: {'Authorization': 'Bearer $token'},
@@ -150,7 +154,10 @@ class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource {
}
@override
Future<void> denyAllocation({required String token, required String allocationToken}) async {
Future<void> denyAllocation({
required String token,
required String allocationToken,
}) async {
await _httpClient.delete(
'/steward-allocation/0/?steward_allocation_key=$allocationToken',
headers: {'Authorization': 'Bearer $token'},
@@ -174,8 +181,9 @@ class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource {
var res = await _httpClient.get(
'/roles-products/?role=Steward',
headers: {'Authorization': 'Bearer $token'},
fromJsonList: (json) =>
json.map((item) => ProductModel.fromJson(item as Map<String, dynamic>)).toList(),
fromJsonList: (json) => json
.map((item) => ProductModel.fromJson(item as Map<String, dynamic>))
.toList(),
);
return res.data;
}
@@ -189,8 +197,9 @@ class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource {
'/guilds/',
queryParameters: queryParameters,
headers: {'Authorization': 'Bearer $token'},
fromJsonList: (json) =>
json.map((item) => GuildModel.fromJson(item as Map<String, dynamic>)).toList(),
fromJsonList: (json) => json
.map((item) => GuildModel.fromJson(item as Map<String, dynamic>))
.toList(),
);
return res.data;
}
@@ -270,7 +279,8 @@ class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource {
}
@override
Future<PaginationModel<StewardFreeBar>?> getStewardPurchasesOutSideOfTheProvince({
Future<PaginationModel<StewardFreeBar>?>
getStewardPurchasesOutSideOfTheProvince({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
@@ -287,22 +297,34 @@ class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource {
}
@override
Future<List<IranProvinceCityModel>?> getCity({required String provinceName}) async {
Future<List<IranProvinceCityModel>?> getCity({
required String provinceName,
}) async {
var res = await _httpClient.get(
'/iran_city/',
queryParameters: {'name': provinceName},
fromJsonList: (json) =>
json.map((item) => IranProvinceCityModel.fromJson(item as Map<String, dynamic>)).toList(),
fromJsonList: (json) => json
.map(
(item) =>
IranProvinceCityModel.fromJson(item as Map<String, dynamic>),
)
.toList(),
);
return res.data;
}
@override
Future<List<IranProvinceCityModel>?> getProvince({CancelToken? cancelToken}) async {
Future<List<IranProvinceCityModel>?> getProvince({
CancelToken? cancelToken,
}) async {
var res = await _httpClient.get(
'/iran_province/',
fromJsonList: (json) =>
json.map((item) => IranProvinceCityModel.fromJson(item as Map<String, dynamic>)).toList(),
fromJsonList: (json) => json
.map(
(item) =>
IranProvinceCityModel.fromJson(item as Map<String, dynamic>),
)
.toList(),
);
return res.data;
}
@@ -315,7 +337,7 @@ class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource {
await _httpClient.post(
'/steward_free_bar/',
headers: {'Authorization': 'Bearer $token'},
data: body.toJson()..removeWhere((key, value) => value==null,),
data: body.toJson()..removeWhere((key, value) => value == null),
);
}
@@ -346,7 +368,8 @@ class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource {
}
@override
Future<PaginationModel<OutProvinceCarcassesBuyer>?> getOutProvinceCarcassesBuyer({
Future<PaginationModel<OutProvinceCarcassesBuyer>?>
getOutProvinceCarcassesBuyer({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
@@ -356,7 +379,8 @@ class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource {
headers: {'Authorization': 'Bearer $token'},
fromJson: (json) => PaginationModel<OutProvinceCarcassesBuyer>.fromJson(
json,
(json) => OutProvinceCarcassesBuyer.fromJson(json as Map<String, dynamic>),
(json) =>
OutProvinceCarcassesBuyer.fromJson(json as Map<String, dynamic>),
),
);
return res.data;
@@ -412,13 +436,19 @@ class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource {
'/steward_free_sale_bar/0/',
data: body.toJson()
..removeWhere((key, value) => value == null)
..addAll({'carcassWeight': body.weightOfCarcasses, 'carcassCount': body.numberOfCarcasses}),
..addAll({
'carcassWeight': body.weightOfCarcasses,
'carcassCount': body.numberOfCarcasses,
}),
headers: {'Authorization': 'Bearer $token'},
);
}
@override
Future<void> deleteOutProvinceStewardFreeBar({required String token, required String key}) async {
Future<void> deleteOutProvinceStewardFreeBar({
required String token,
required String key,
}) async {
await _httpClient.delete(
'/steward_free_sale_bar/0/',
queryParameters: {'key': key},
@@ -438,7 +468,10 @@ class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource {
}
@override
Future<void> updateUserProfile({required String token, required UserProfile userProfile}) async {
Future<void> updateUserProfile({
required String token,
required UserProfile userProfile,
}) async {
await _httpClient.put(
'/system_user_profile/0/',
headers: {'Authorization': 'Bearer $token'},
@@ -476,7 +509,10 @@ class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource {
}
@override
Future<void> createSegmentation({required String token, required SegmentationModel model}) async {
Future<void> createSegmentation({
required String token,
required SegmentationModel model,
}) async {
await _httpClient.post(
'/app-segmentation/',
data: model.toJson()..removeWhere((key, value) => value == null),
@@ -485,7 +521,10 @@ class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource {
}
@override
Future<void> editSegmentation({required String token, required SegmentationModel model}) async {
Future<void> editSegmentation({
required String token,
required SegmentationModel model,
}) async {
await _httpClient.put(
'/app-segmentation/0/',
data: model.toJson()..removeWhere((key, value) => value == null),
@@ -536,7 +575,9 @@ class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource {
}
@override
Future<StewardRemainWeight?> getStewardRemainWeight({required String token}) async {
Future<StewardRemainWeight?> getStewardRemainWeight({
required String token,
}) async {
var res = await _httpClient.get(
'/steward-remain-weight/',
headers: {'Authorization': 'Bearer $token'},
@@ -545,4 +586,5 @@ class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource {
return res.data;
}
}

View File

@@ -2,8 +2,12 @@ import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_house/kill_house_response.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_request_list/kill_request_list.dart'
as listModel;
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_sales_info_dashboard.dart';
import 'package:rasadyar_core/core.dart';
abstract class KillHouseRemoteDataSource {
//region requestKill
Future<List<KillHouseResponse>?> getKillHouseList({
required String token,
Map<String, dynamic>? queryParameters,
@@ -22,4 +26,21 @@ abstract class KillHouseRemoteDataSource {
});
Future<void> deleteKillRequest({required String token, required int requestId});
//endregion
//region warehouseAndDistribution
Future<KillHouseSalesInfoDashboard?> getKillHouseSalesInfoDashboard({
required String token,
CancelToken? cancelToken,
Map<String, dynamic>? queryParameters,
});
//endregion
}

View File

@@ -3,6 +3,7 @@ import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_house/kill_house_response.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_request_list/kill_request_list.dart'
as listModel;
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_sales_info_dashboard.dart';
import 'package:rasadyar_core/core.dart';
class KillHouseRemoteDataSourceImpl extends KillHouseRemoteDataSource {
@@ -20,7 +21,9 @@ class KillHouseRemoteDataSourceImpl extends KillHouseRemoteDataSource {
headers: {'Authorization': 'Bearer $token'},
fromJson: (json) {
var data = json['results'] as List<dynamic>;
return ChickenCommissionPrices.fromJson(data.first as Map<String, dynamic>);
return ChickenCommissionPrices.fromJson(
data.first as Map<String, dynamic>,
);
},
);
@@ -35,8 +38,9 @@ class KillHouseRemoteDataSourceImpl extends KillHouseRemoteDataSource {
var res = await _httpClient.get(
'/kill_house/?kill_house',
headers: {'Authorization': 'Bearer $token'},
fromJsonList: (json) =>
json.map((e) => KillHouseResponse.fromJson(e as Map<String, dynamic>)).toList(),
fromJsonList: (json) => json
.map((e) => KillHouseResponse.fromJson(e as Map<String, dynamic>))
.toList(),
);
return res.data;
@@ -63,18 +67,47 @@ class KillHouseRemoteDataSourceImpl extends KillHouseRemoteDataSource {
'/kill_request/',
headers: {'Authorization': 'Bearer $token'},
queryParameters: queryParameters,
fromJsonList: (json) =>
json.map((e) => listModel.KillRequestList.fromJson(e as Map<String, dynamic>)).toList(),
fromJsonList: (json) => json
.map(
(e) =>
listModel.KillRequestList.fromJson(e as Map<String, dynamic>),
)
.toList(),
);
return res.data;
}
@override
Future<void> deleteKillRequest({required String token, required int requestId}) async {
Future<void> deleteKillRequest({
required String token,
required int requestId,
}) async {
await _httpClient.delete(
'/kill_request/$requestId/',
headers: {'Authorization': 'Bearer $token'},
);
}
//endregion
//region warehouseAndDistribution
@override
Future<KillHouseSalesInfoDashboard?> getKillHouseSalesInfoDashboard({
required String token,
CancelToken? cancelToken,
Map<String, dynamic>? queryParameters,
}) async {
var res = await _httpClient.get(
'/kill-house-sales-info-dashboard/?role=KillHouse',
cancelToken: cancelToken,
headers: {'Authorization': 'Bearer $token'},
queryParameters: queryParameters,
fromJson: KillHouseSalesInfoDashboard.fromJson,
);
return res.data;
}
//endregion
}

View File

@@ -0,0 +1,35 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'kill_house_sales_info_dashboard.freezed.dart';
part 'kill_house_sales_info_dashboard.g.dart';
@freezed
abstract class KillHouseSalesInfoDashboard with _$KillHouseSalesInfoDashboard {
const factory KillHouseSalesInfoDashboard({
double? totalGovernmentalInputWeight,
double? totalFreeInputWeight,
double? totalGovernmentalOutputWeight,
double? totalFreeOutputWeight,
double? totalGovernmentalRemainWeight,
double? totalFreeRemainWeight,
@JsonKey(name: 'total_kill_house_free_sale__bar_carcasses_weight')
double? totalKillHouseFreeSaleBarCarcassesWeight,
double? totalKillHouseAllocationsWeight,
double? segmentationsWeight,
double? coldHouseAllocationsWeight,
double? totalSellingInProvinceGovernmentalWeight,
double? totalSellingInProvinceFreeWeight,
double? totalCommitmentSellingInProvinceGovernmentalWeight,
double? totalCommitmentSellingInProvinceGovernmentalRemainWeight,
double? totalCommitmentSellingInProvinceFreeWeight,
double? totalCommitmentSellingInProvinceFreeRemainWeight,
double? posAllocatedWeight,
double? posGovernmentalAllocatedWeight,
double? posFreeAllocatedWeight,
double? wareHouseArchiveGovernmentalWeight,
double? wareHouseArchiveFreeWeight,
}) = _KillHouseSalesInfoDashboard;
factory KillHouseSalesInfoDashboard.fromJson(Map<String, dynamic> json) =>
_$KillHouseSalesInfoDashboardFromJson(json);
}

View File

@@ -0,0 +1,337 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'kill_house_sales_info_dashboard.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$KillHouseSalesInfoDashboard {
double? get totalGovernmentalInputWeight; double? get totalFreeInputWeight; double? get totalGovernmentalOutputWeight; double? get totalFreeOutputWeight; double? get totalGovernmentalRemainWeight; double? get totalFreeRemainWeight;@JsonKey(name: 'total_kill_house_free_sale__bar_carcasses_weight') double? get totalKillHouseFreeSaleBarCarcassesWeight; double? get totalKillHouseAllocationsWeight; double? get segmentationsWeight; double? get coldHouseAllocationsWeight; double? get totalSellingInProvinceGovernmentalWeight; double? get totalSellingInProvinceFreeWeight; double? get totalCommitmentSellingInProvinceGovernmentalWeight; double? get totalCommitmentSellingInProvinceGovernmentalRemainWeight; double? get totalCommitmentSellingInProvinceFreeWeight; double? get totalCommitmentSellingInProvinceFreeRemainWeight; double? get posAllocatedWeight; double? get posGovernmentalAllocatedWeight; double? get posFreeAllocatedWeight; double? get wareHouseArchiveGovernmentalWeight; double? get wareHouseArchiveFreeWeight;
/// Create a copy of KillHouseSalesInfoDashboard
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$KillHouseSalesInfoDashboardCopyWith<KillHouseSalesInfoDashboard> get copyWith => _$KillHouseSalesInfoDashboardCopyWithImpl<KillHouseSalesInfoDashboard>(this as KillHouseSalesInfoDashboard, _$identity);
/// Serializes this KillHouseSalesInfoDashboard to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is KillHouseSalesInfoDashboard&&(identical(other.totalGovernmentalInputWeight, totalGovernmentalInputWeight) || other.totalGovernmentalInputWeight == totalGovernmentalInputWeight)&&(identical(other.totalFreeInputWeight, totalFreeInputWeight) || other.totalFreeInputWeight == totalFreeInputWeight)&&(identical(other.totalGovernmentalOutputWeight, totalGovernmentalOutputWeight) || other.totalGovernmentalOutputWeight == totalGovernmentalOutputWeight)&&(identical(other.totalFreeOutputWeight, totalFreeOutputWeight) || other.totalFreeOutputWeight == totalFreeOutputWeight)&&(identical(other.totalGovernmentalRemainWeight, totalGovernmentalRemainWeight) || other.totalGovernmentalRemainWeight == totalGovernmentalRemainWeight)&&(identical(other.totalFreeRemainWeight, totalFreeRemainWeight) || other.totalFreeRemainWeight == totalFreeRemainWeight)&&(identical(other.totalKillHouseFreeSaleBarCarcassesWeight, totalKillHouseFreeSaleBarCarcassesWeight) || other.totalKillHouseFreeSaleBarCarcassesWeight == totalKillHouseFreeSaleBarCarcassesWeight)&&(identical(other.totalKillHouseAllocationsWeight, totalKillHouseAllocationsWeight) || other.totalKillHouseAllocationsWeight == totalKillHouseAllocationsWeight)&&(identical(other.segmentationsWeight, segmentationsWeight) || other.segmentationsWeight == segmentationsWeight)&&(identical(other.coldHouseAllocationsWeight, coldHouseAllocationsWeight) || other.coldHouseAllocationsWeight == coldHouseAllocationsWeight)&&(identical(other.totalSellingInProvinceGovernmentalWeight, totalSellingInProvinceGovernmentalWeight) || other.totalSellingInProvinceGovernmentalWeight == totalSellingInProvinceGovernmentalWeight)&&(identical(other.totalSellingInProvinceFreeWeight, totalSellingInProvinceFreeWeight) || other.totalSellingInProvinceFreeWeight == totalSellingInProvinceFreeWeight)&&(identical(other.totalCommitmentSellingInProvinceGovernmentalWeight, totalCommitmentSellingInProvinceGovernmentalWeight) || other.totalCommitmentSellingInProvinceGovernmentalWeight == totalCommitmentSellingInProvinceGovernmentalWeight)&&(identical(other.totalCommitmentSellingInProvinceGovernmentalRemainWeight, totalCommitmentSellingInProvinceGovernmentalRemainWeight) || other.totalCommitmentSellingInProvinceGovernmentalRemainWeight == totalCommitmentSellingInProvinceGovernmentalRemainWeight)&&(identical(other.totalCommitmentSellingInProvinceFreeWeight, totalCommitmentSellingInProvinceFreeWeight) || other.totalCommitmentSellingInProvinceFreeWeight == totalCommitmentSellingInProvinceFreeWeight)&&(identical(other.totalCommitmentSellingInProvinceFreeRemainWeight, totalCommitmentSellingInProvinceFreeRemainWeight) || other.totalCommitmentSellingInProvinceFreeRemainWeight == totalCommitmentSellingInProvinceFreeRemainWeight)&&(identical(other.posAllocatedWeight, posAllocatedWeight) || other.posAllocatedWeight == posAllocatedWeight)&&(identical(other.posGovernmentalAllocatedWeight, posGovernmentalAllocatedWeight) || other.posGovernmentalAllocatedWeight == posGovernmentalAllocatedWeight)&&(identical(other.posFreeAllocatedWeight, posFreeAllocatedWeight) || other.posFreeAllocatedWeight == posFreeAllocatedWeight)&&(identical(other.wareHouseArchiveGovernmentalWeight, wareHouseArchiveGovernmentalWeight) || other.wareHouseArchiveGovernmentalWeight == wareHouseArchiveGovernmentalWeight)&&(identical(other.wareHouseArchiveFreeWeight, wareHouseArchiveFreeWeight) || other.wareHouseArchiveFreeWeight == wareHouseArchiveFreeWeight));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hashAll([runtimeType,totalGovernmentalInputWeight,totalFreeInputWeight,totalGovernmentalOutputWeight,totalFreeOutputWeight,totalGovernmentalRemainWeight,totalFreeRemainWeight,totalKillHouseFreeSaleBarCarcassesWeight,totalKillHouseAllocationsWeight,segmentationsWeight,coldHouseAllocationsWeight,totalSellingInProvinceGovernmentalWeight,totalSellingInProvinceFreeWeight,totalCommitmentSellingInProvinceGovernmentalWeight,totalCommitmentSellingInProvinceGovernmentalRemainWeight,totalCommitmentSellingInProvinceFreeWeight,totalCommitmentSellingInProvinceFreeRemainWeight,posAllocatedWeight,posGovernmentalAllocatedWeight,posFreeAllocatedWeight,wareHouseArchiveGovernmentalWeight,wareHouseArchiveFreeWeight]);
@override
String toString() {
return 'KillHouseSalesInfoDashboard(totalGovernmentalInputWeight: $totalGovernmentalInputWeight, totalFreeInputWeight: $totalFreeInputWeight, totalGovernmentalOutputWeight: $totalGovernmentalOutputWeight, totalFreeOutputWeight: $totalFreeOutputWeight, totalGovernmentalRemainWeight: $totalGovernmentalRemainWeight, totalFreeRemainWeight: $totalFreeRemainWeight, totalKillHouseFreeSaleBarCarcassesWeight: $totalKillHouseFreeSaleBarCarcassesWeight, totalKillHouseAllocationsWeight: $totalKillHouseAllocationsWeight, segmentationsWeight: $segmentationsWeight, coldHouseAllocationsWeight: $coldHouseAllocationsWeight, totalSellingInProvinceGovernmentalWeight: $totalSellingInProvinceGovernmentalWeight, totalSellingInProvinceFreeWeight: $totalSellingInProvinceFreeWeight, totalCommitmentSellingInProvinceGovernmentalWeight: $totalCommitmentSellingInProvinceGovernmentalWeight, totalCommitmentSellingInProvinceGovernmentalRemainWeight: $totalCommitmentSellingInProvinceGovernmentalRemainWeight, totalCommitmentSellingInProvinceFreeWeight: $totalCommitmentSellingInProvinceFreeWeight, totalCommitmentSellingInProvinceFreeRemainWeight: $totalCommitmentSellingInProvinceFreeRemainWeight, posAllocatedWeight: $posAllocatedWeight, posGovernmentalAllocatedWeight: $posGovernmentalAllocatedWeight, posFreeAllocatedWeight: $posFreeAllocatedWeight, wareHouseArchiveGovernmentalWeight: $wareHouseArchiveGovernmentalWeight, wareHouseArchiveFreeWeight: $wareHouseArchiveFreeWeight)';
}
}
/// @nodoc
abstract mixin class $KillHouseSalesInfoDashboardCopyWith<$Res> {
factory $KillHouseSalesInfoDashboardCopyWith(KillHouseSalesInfoDashboard value, $Res Function(KillHouseSalesInfoDashboard) _then) = _$KillHouseSalesInfoDashboardCopyWithImpl;
@useResult
$Res call({
double? totalGovernmentalInputWeight, double? totalFreeInputWeight, double? totalGovernmentalOutputWeight, double? totalFreeOutputWeight, double? totalGovernmentalRemainWeight, double? totalFreeRemainWeight,@JsonKey(name: 'total_kill_house_free_sale__bar_carcasses_weight') double? totalKillHouseFreeSaleBarCarcassesWeight, double? totalKillHouseAllocationsWeight, double? segmentationsWeight, double? coldHouseAllocationsWeight, double? totalSellingInProvinceGovernmentalWeight, double? totalSellingInProvinceFreeWeight, double? totalCommitmentSellingInProvinceGovernmentalWeight, double? totalCommitmentSellingInProvinceGovernmentalRemainWeight, double? totalCommitmentSellingInProvinceFreeWeight, double? totalCommitmentSellingInProvinceFreeRemainWeight, double? posAllocatedWeight, double? posGovernmentalAllocatedWeight, double? posFreeAllocatedWeight, double? wareHouseArchiveGovernmentalWeight, double? wareHouseArchiveFreeWeight
});
}
/// @nodoc
class _$KillHouseSalesInfoDashboardCopyWithImpl<$Res>
implements $KillHouseSalesInfoDashboardCopyWith<$Res> {
_$KillHouseSalesInfoDashboardCopyWithImpl(this._self, this._then);
final KillHouseSalesInfoDashboard _self;
final $Res Function(KillHouseSalesInfoDashboard) _then;
/// Create a copy of KillHouseSalesInfoDashboard
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? totalGovernmentalInputWeight = freezed,Object? totalFreeInputWeight = freezed,Object? totalGovernmentalOutputWeight = freezed,Object? totalFreeOutputWeight = freezed,Object? totalGovernmentalRemainWeight = freezed,Object? totalFreeRemainWeight = freezed,Object? totalKillHouseFreeSaleBarCarcassesWeight = freezed,Object? totalKillHouseAllocationsWeight = freezed,Object? segmentationsWeight = freezed,Object? coldHouseAllocationsWeight = freezed,Object? totalSellingInProvinceGovernmentalWeight = freezed,Object? totalSellingInProvinceFreeWeight = freezed,Object? totalCommitmentSellingInProvinceGovernmentalWeight = freezed,Object? totalCommitmentSellingInProvinceGovernmentalRemainWeight = freezed,Object? totalCommitmentSellingInProvinceFreeWeight = freezed,Object? totalCommitmentSellingInProvinceFreeRemainWeight = freezed,Object? posAllocatedWeight = freezed,Object? posGovernmentalAllocatedWeight = freezed,Object? posFreeAllocatedWeight = freezed,Object? wareHouseArchiveGovernmentalWeight = freezed,Object? wareHouseArchiveFreeWeight = freezed,}) {
return _then(_self.copyWith(
totalGovernmentalInputWeight: freezed == totalGovernmentalInputWeight ? _self.totalGovernmentalInputWeight : totalGovernmentalInputWeight // ignore: cast_nullable_to_non_nullable
as double?,totalFreeInputWeight: freezed == totalFreeInputWeight ? _self.totalFreeInputWeight : totalFreeInputWeight // ignore: cast_nullable_to_non_nullable
as double?,totalGovernmentalOutputWeight: freezed == totalGovernmentalOutputWeight ? _self.totalGovernmentalOutputWeight : totalGovernmentalOutputWeight // ignore: cast_nullable_to_non_nullable
as double?,totalFreeOutputWeight: freezed == totalFreeOutputWeight ? _self.totalFreeOutputWeight : totalFreeOutputWeight // ignore: cast_nullable_to_non_nullable
as double?,totalGovernmentalRemainWeight: freezed == totalGovernmentalRemainWeight ? _self.totalGovernmentalRemainWeight : totalGovernmentalRemainWeight // ignore: cast_nullable_to_non_nullable
as double?,totalFreeRemainWeight: freezed == totalFreeRemainWeight ? _self.totalFreeRemainWeight : totalFreeRemainWeight // ignore: cast_nullable_to_non_nullable
as double?,totalKillHouseFreeSaleBarCarcassesWeight: freezed == totalKillHouseFreeSaleBarCarcassesWeight ? _self.totalKillHouseFreeSaleBarCarcassesWeight : totalKillHouseFreeSaleBarCarcassesWeight // ignore: cast_nullable_to_non_nullable
as double?,totalKillHouseAllocationsWeight: freezed == totalKillHouseAllocationsWeight ? _self.totalKillHouseAllocationsWeight : totalKillHouseAllocationsWeight // ignore: cast_nullable_to_non_nullable
as double?,segmentationsWeight: freezed == segmentationsWeight ? _self.segmentationsWeight : segmentationsWeight // ignore: cast_nullable_to_non_nullable
as double?,coldHouseAllocationsWeight: freezed == coldHouseAllocationsWeight ? _self.coldHouseAllocationsWeight : coldHouseAllocationsWeight // ignore: cast_nullable_to_non_nullable
as double?,totalSellingInProvinceGovernmentalWeight: freezed == totalSellingInProvinceGovernmentalWeight ? _self.totalSellingInProvinceGovernmentalWeight : totalSellingInProvinceGovernmentalWeight // ignore: cast_nullable_to_non_nullable
as double?,totalSellingInProvinceFreeWeight: freezed == totalSellingInProvinceFreeWeight ? _self.totalSellingInProvinceFreeWeight : totalSellingInProvinceFreeWeight // ignore: cast_nullable_to_non_nullable
as double?,totalCommitmentSellingInProvinceGovernmentalWeight: freezed == totalCommitmentSellingInProvinceGovernmentalWeight ? _self.totalCommitmentSellingInProvinceGovernmentalWeight : totalCommitmentSellingInProvinceGovernmentalWeight // ignore: cast_nullable_to_non_nullable
as double?,totalCommitmentSellingInProvinceGovernmentalRemainWeight: freezed == totalCommitmentSellingInProvinceGovernmentalRemainWeight ? _self.totalCommitmentSellingInProvinceGovernmentalRemainWeight : totalCommitmentSellingInProvinceGovernmentalRemainWeight // ignore: cast_nullable_to_non_nullable
as double?,totalCommitmentSellingInProvinceFreeWeight: freezed == totalCommitmentSellingInProvinceFreeWeight ? _self.totalCommitmentSellingInProvinceFreeWeight : totalCommitmentSellingInProvinceFreeWeight // ignore: cast_nullable_to_non_nullable
as double?,totalCommitmentSellingInProvinceFreeRemainWeight: freezed == totalCommitmentSellingInProvinceFreeRemainWeight ? _self.totalCommitmentSellingInProvinceFreeRemainWeight : totalCommitmentSellingInProvinceFreeRemainWeight // ignore: cast_nullable_to_non_nullable
as double?,posAllocatedWeight: freezed == posAllocatedWeight ? _self.posAllocatedWeight : posAllocatedWeight // ignore: cast_nullable_to_non_nullable
as double?,posGovernmentalAllocatedWeight: freezed == posGovernmentalAllocatedWeight ? _self.posGovernmentalAllocatedWeight : posGovernmentalAllocatedWeight // ignore: cast_nullable_to_non_nullable
as double?,posFreeAllocatedWeight: freezed == posFreeAllocatedWeight ? _self.posFreeAllocatedWeight : posFreeAllocatedWeight // ignore: cast_nullable_to_non_nullable
as double?,wareHouseArchiveGovernmentalWeight: freezed == wareHouseArchiveGovernmentalWeight ? _self.wareHouseArchiveGovernmentalWeight : wareHouseArchiveGovernmentalWeight // ignore: cast_nullable_to_non_nullable
as double?,wareHouseArchiveFreeWeight: freezed == wareHouseArchiveFreeWeight ? _self.wareHouseArchiveFreeWeight : wareHouseArchiveFreeWeight // ignore: cast_nullable_to_non_nullable
as double?,
));
}
}
/// Adds pattern-matching-related methods to [KillHouseSalesInfoDashboard].
extension KillHouseSalesInfoDashboardPatterns on KillHouseSalesInfoDashboard {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _KillHouseSalesInfoDashboard value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _KillHouseSalesInfoDashboard() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _KillHouseSalesInfoDashboard value) $default,){
final _that = this;
switch (_that) {
case _KillHouseSalesInfoDashboard():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _KillHouseSalesInfoDashboard value)? $default,){
final _that = this;
switch (_that) {
case _KillHouseSalesInfoDashboard() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( double? totalGovernmentalInputWeight, double? totalFreeInputWeight, double? totalGovernmentalOutputWeight, double? totalFreeOutputWeight, double? totalGovernmentalRemainWeight, double? totalFreeRemainWeight, @JsonKey(name: 'total_kill_house_free_sale__bar_carcasses_weight') double? totalKillHouseFreeSaleBarCarcassesWeight, double? totalKillHouseAllocationsWeight, double? segmentationsWeight, double? coldHouseAllocationsWeight, double? totalSellingInProvinceGovernmentalWeight, double? totalSellingInProvinceFreeWeight, double? totalCommitmentSellingInProvinceGovernmentalWeight, double? totalCommitmentSellingInProvinceGovernmentalRemainWeight, double? totalCommitmentSellingInProvinceFreeWeight, double? totalCommitmentSellingInProvinceFreeRemainWeight, double? posAllocatedWeight, double? posGovernmentalAllocatedWeight, double? posFreeAllocatedWeight, double? wareHouseArchiveGovernmentalWeight, double? wareHouseArchiveFreeWeight)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _KillHouseSalesInfoDashboard() when $default != null:
return $default(_that.totalGovernmentalInputWeight,_that.totalFreeInputWeight,_that.totalGovernmentalOutputWeight,_that.totalFreeOutputWeight,_that.totalGovernmentalRemainWeight,_that.totalFreeRemainWeight,_that.totalKillHouseFreeSaleBarCarcassesWeight,_that.totalKillHouseAllocationsWeight,_that.segmentationsWeight,_that.coldHouseAllocationsWeight,_that.totalSellingInProvinceGovernmentalWeight,_that.totalSellingInProvinceFreeWeight,_that.totalCommitmentSellingInProvinceGovernmentalWeight,_that.totalCommitmentSellingInProvinceGovernmentalRemainWeight,_that.totalCommitmentSellingInProvinceFreeWeight,_that.totalCommitmentSellingInProvinceFreeRemainWeight,_that.posAllocatedWeight,_that.posGovernmentalAllocatedWeight,_that.posFreeAllocatedWeight,_that.wareHouseArchiveGovernmentalWeight,_that.wareHouseArchiveFreeWeight);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( double? totalGovernmentalInputWeight, double? totalFreeInputWeight, double? totalGovernmentalOutputWeight, double? totalFreeOutputWeight, double? totalGovernmentalRemainWeight, double? totalFreeRemainWeight, @JsonKey(name: 'total_kill_house_free_sale__bar_carcasses_weight') double? totalKillHouseFreeSaleBarCarcassesWeight, double? totalKillHouseAllocationsWeight, double? segmentationsWeight, double? coldHouseAllocationsWeight, double? totalSellingInProvinceGovernmentalWeight, double? totalSellingInProvinceFreeWeight, double? totalCommitmentSellingInProvinceGovernmentalWeight, double? totalCommitmentSellingInProvinceGovernmentalRemainWeight, double? totalCommitmentSellingInProvinceFreeWeight, double? totalCommitmentSellingInProvinceFreeRemainWeight, double? posAllocatedWeight, double? posGovernmentalAllocatedWeight, double? posFreeAllocatedWeight, double? wareHouseArchiveGovernmentalWeight, double? wareHouseArchiveFreeWeight) $default,) {final _that = this;
switch (_that) {
case _KillHouseSalesInfoDashboard():
return $default(_that.totalGovernmentalInputWeight,_that.totalFreeInputWeight,_that.totalGovernmentalOutputWeight,_that.totalFreeOutputWeight,_that.totalGovernmentalRemainWeight,_that.totalFreeRemainWeight,_that.totalKillHouseFreeSaleBarCarcassesWeight,_that.totalKillHouseAllocationsWeight,_that.segmentationsWeight,_that.coldHouseAllocationsWeight,_that.totalSellingInProvinceGovernmentalWeight,_that.totalSellingInProvinceFreeWeight,_that.totalCommitmentSellingInProvinceGovernmentalWeight,_that.totalCommitmentSellingInProvinceGovernmentalRemainWeight,_that.totalCommitmentSellingInProvinceFreeWeight,_that.totalCommitmentSellingInProvinceFreeRemainWeight,_that.posAllocatedWeight,_that.posGovernmentalAllocatedWeight,_that.posFreeAllocatedWeight,_that.wareHouseArchiveGovernmentalWeight,_that.wareHouseArchiveFreeWeight);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( double? totalGovernmentalInputWeight, double? totalFreeInputWeight, double? totalGovernmentalOutputWeight, double? totalFreeOutputWeight, double? totalGovernmentalRemainWeight, double? totalFreeRemainWeight, @JsonKey(name: 'total_kill_house_free_sale__bar_carcasses_weight') double? totalKillHouseFreeSaleBarCarcassesWeight, double? totalKillHouseAllocationsWeight, double? segmentationsWeight, double? coldHouseAllocationsWeight, double? totalSellingInProvinceGovernmentalWeight, double? totalSellingInProvinceFreeWeight, double? totalCommitmentSellingInProvinceGovernmentalWeight, double? totalCommitmentSellingInProvinceGovernmentalRemainWeight, double? totalCommitmentSellingInProvinceFreeWeight, double? totalCommitmentSellingInProvinceFreeRemainWeight, double? posAllocatedWeight, double? posGovernmentalAllocatedWeight, double? posFreeAllocatedWeight, double? wareHouseArchiveGovernmentalWeight, double? wareHouseArchiveFreeWeight)? $default,) {final _that = this;
switch (_that) {
case _KillHouseSalesInfoDashboard() when $default != null:
return $default(_that.totalGovernmentalInputWeight,_that.totalFreeInputWeight,_that.totalGovernmentalOutputWeight,_that.totalFreeOutputWeight,_that.totalGovernmentalRemainWeight,_that.totalFreeRemainWeight,_that.totalKillHouseFreeSaleBarCarcassesWeight,_that.totalKillHouseAllocationsWeight,_that.segmentationsWeight,_that.coldHouseAllocationsWeight,_that.totalSellingInProvinceGovernmentalWeight,_that.totalSellingInProvinceFreeWeight,_that.totalCommitmentSellingInProvinceGovernmentalWeight,_that.totalCommitmentSellingInProvinceGovernmentalRemainWeight,_that.totalCommitmentSellingInProvinceFreeWeight,_that.totalCommitmentSellingInProvinceFreeRemainWeight,_that.posAllocatedWeight,_that.posGovernmentalAllocatedWeight,_that.posFreeAllocatedWeight,_that.wareHouseArchiveGovernmentalWeight,_that.wareHouseArchiveFreeWeight);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _KillHouseSalesInfoDashboard implements KillHouseSalesInfoDashboard {
const _KillHouseSalesInfoDashboard({this.totalGovernmentalInputWeight, this.totalFreeInputWeight, this.totalGovernmentalOutputWeight, this.totalFreeOutputWeight, this.totalGovernmentalRemainWeight, this.totalFreeRemainWeight, @JsonKey(name: 'total_kill_house_free_sale__bar_carcasses_weight') this.totalKillHouseFreeSaleBarCarcassesWeight, this.totalKillHouseAllocationsWeight, this.segmentationsWeight, this.coldHouseAllocationsWeight, this.totalSellingInProvinceGovernmentalWeight, this.totalSellingInProvinceFreeWeight, this.totalCommitmentSellingInProvinceGovernmentalWeight, this.totalCommitmentSellingInProvinceGovernmentalRemainWeight, this.totalCommitmentSellingInProvinceFreeWeight, this.totalCommitmentSellingInProvinceFreeRemainWeight, this.posAllocatedWeight, this.posGovernmentalAllocatedWeight, this.posFreeAllocatedWeight, this.wareHouseArchiveGovernmentalWeight, this.wareHouseArchiveFreeWeight});
factory _KillHouseSalesInfoDashboard.fromJson(Map<String, dynamic> json) => _$KillHouseSalesInfoDashboardFromJson(json);
@override final double? totalGovernmentalInputWeight;
@override final double? totalFreeInputWeight;
@override final double? totalGovernmentalOutputWeight;
@override final double? totalFreeOutputWeight;
@override final double? totalGovernmentalRemainWeight;
@override final double? totalFreeRemainWeight;
@override@JsonKey(name: 'total_kill_house_free_sale__bar_carcasses_weight') final double? totalKillHouseFreeSaleBarCarcassesWeight;
@override final double? totalKillHouseAllocationsWeight;
@override final double? segmentationsWeight;
@override final double? coldHouseAllocationsWeight;
@override final double? totalSellingInProvinceGovernmentalWeight;
@override final double? totalSellingInProvinceFreeWeight;
@override final double? totalCommitmentSellingInProvinceGovernmentalWeight;
@override final double? totalCommitmentSellingInProvinceGovernmentalRemainWeight;
@override final double? totalCommitmentSellingInProvinceFreeWeight;
@override final double? totalCommitmentSellingInProvinceFreeRemainWeight;
@override final double? posAllocatedWeight;
@override final double? posGovernmentalAllocatedWeight;
@override final double? posFreeAllocatedWeight;
@override final double? wareHouseArchiveGovernmentalWeight;
@override final double? wareHouseArchiveFreeWeight;
/// Create a copy of KillHouseSalesInfoDashboard
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$KillHouseSalesInfoDashboardCopyWith<_KillHouseSalesInfoDashboard> get copyWith => __$KillHouseSalesInfoDashboardCopyWithImpl<_KillHouseSalesInfoDashboard>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$KillHouseSalesInfoDashboardToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _KillHouseSalesInfoDashboard&&(identical(other.totalGovernmentalInputWeight, totalGovernmentalInputWeight) || other.totalGovernmentalInputWeight == totalGovernmentalInputWeight)&&(identical(other.totalFreeInputWeight, totalFreeInputWeight) || other.totalFreeInputWeight == totalFreeInputWeight)&&(identical(other.totalGovernmentalOutputWeight, totalGovernmentalOutputWeight) || other.totalGovernmentalOutputWeight == totalGovernmentalOutputWeight)&&(identical(other.totalFreeOutputWeight, totalFreeOutputWeight) || other.totalFreeOutputWeight == totalFreeOutputWeight)&&(identical(other.totalGovernmentalRemainWeight, totalGovernmentalRemainWeight) || other.totalGovernmentalRemainWeight == totalGovernmentalRemainWeight)&&(identical(other.totalFreeRemainWeight, totalFreeRemainWeight) || other.totalFreeRemainWeight == totalFreeRemainWeight)&&(identical(other.totalKillHouseFreeSaleBarCarcassesWeight, totalKillHouseFreeSaleBarCarcassesWeight) || other.totalKillHouseFreeSaleBarCarcassesWeight == totalKillHouseFreeSaleBarCarcassesWeight)&&(identical(other.totalKillHouseAllocationsWeight, totalKillHouseAllocationsWeight) || other.totalKillHouseAllocationsWeight == totalKillHouseAllocationsWeight)&&(identical(other.segmentationsWeight, segmentationsWeight) || other.segmentationsWeight == segmentationsWeight)&&(identical(other.coldHouseAllocationsWeight, coldHouseAllocationsWeight) || other.coldHouseAllocationsWeight == coldHouseAllocationsWeight)&&(identical(other.totalSellingInProvinceGovernmentalWeight, totalSellingInProvinceGovernmentalWeight) || other.totalSellingInProvinceGovernmentalWeight == totalSellingInProvinceGovernmentalWeight)&&(identical(other.totalSellingInProvinceFreeWeight, totalSellingInProvinceFreeWeight) || other.totalSellingInProvinceFreeWeight == totalSellingInProvinceFreeWeight)&&(identical(other.totalCommitmentSellingInProvinceGovernmentalWeight, totalCommitmentSellingInProvinceGovernmentalWeight) || other.totalCommitmentSellingInProvinceGovernmentalWeight == totalCommitmentSellingInProvinceGovernmentalWeight)&&(identical(other.totalCommitmentSellingInProvinceGovernmentalRemainWeight, totalCommitmentSellingInProvinceGovernmentalRemainWeight) || other.totalCommitmentSellingInProvinceGovernmentalRemainWeight == totalCommitmentSellingInProvinceGovernmentalRemainWeight)&&(identical(other.totalCommitmentSellingInProvinceFreeWeight, totalCommitmentSellingInProvinceFreeWeight) || other.totalCommitmentSellingInProvinceFreeWeight == totalCommitmentSellingInProvinceFreeWeight)&&(identical(other.totalCommitmentSellingInProvinceFreeRemainWeight, totalCommitmentSellingInProvinceFreeRemainWeight) || other.totalCommitmentSellingInProvinceFreeRemainWeight == totalCommitmentSellingInProvinceFreeRemainWeight)&&(identical(other.posAllocatedWeight, posAllocatedWeight) || other.posAllocatedWeight == posAllocatedWeight)&&(identical(other.posGovernmentalAllocatedWeight, posGovernmentalAllocatedWeight) || other.posGovernmentalAllocatedWeight == posGovernmentalAllocatedWeight)&&(identical(other.posFreeAllocatedWeight, posFreeAllocatedWeight) || other.posFreeAllocatedWeight == posFreeAllocatedWeight)&&(identical(other.wareHouseArchiveGovernmentalWeight, wareHouseArchiveGovernmentalWeight) || other.wareHouseArchiveGovernmentalWeight == wareHouseArchiveGovernmentalWeight)&&(identical(other.wareHouseArchiveFreeWeight, wareHouseArchiveFreeWeight) || other.wareHouseArchiveFreeWeight == wareHouseArchiveFreeWeight));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hashAll([runtimeType,totalGovernmentalInputWeight,totalFreeInputWeight,totalGovernmentalOutputWeight,totalFreeOutputWeight,totalGovernmentalRemainWeight,totalFreeRemainWeight,totalKillHouseFreeSaleBarCarcassesWeight,totalKillHouseAllocationsWeight,segmentationsWeight,coldHouseAllocationsWeight,totalSellingInProvinceGovernmentalWeight,totalSellingInProvinceFreeWeight,totalCommitmentSellingInProvinceGovernmentalWeight,totalCommitmentSellingInProvinceGovernmentalRemainWeight,totalCommitmentSellingInProvinceFreeWeight,totalCommitmentSellingInProvinceFreeRemainWeight,posAllocatedWeight,posGovernmentalAllocatedWeight,posFreeAllocatedWeight,wareHouseArchiveGovernmentalWeight,wareHouseArchiveFreeWeight]);
@override
String toString() {
return 'KillHouseSalesInfoDashboard(totalGovernmentalInputWeight: $totalGovernmentalInputWeight, totalFreeInputWeight: $totalFreeInputWeight, totalGovernmentalOutputWeight: $totalGovernmentalOutputWeight, totalFreeOutputWeight: $totalFreeOutputWeight, totalGovernmentalRemainWeight: $totalGovernmentalRemainWeight, totalFreeRemainWeight: $totalFreeRemainWeight, totalKillHouseFreeSaleBarCarcassesWeight: $totalKillHouseFreeSaleBarCarcassesWeight, totalKillHouseAllocationsWeight: $totalKillHouseAllocationsWeight, segmentationsWeight: $segmentationsWeight, coldHouseAllocationsWeight: $coldHouseAllocationsWeight, totalSellingInProvinceGovernmentalWeight: $totalSellingInProvinceGovernmentalWeight, totalSellingInProvinceFreeWeight: $totalSellingInProvinceFreeWeight, totalCommitmentSellingInProvinceGovernmentalWeight: $totalCommitmentSellingInProvinceGovernmentalWeight, totalCommitmentSellingInProvinceGovernmentalRemainWeight: $totalCommitmentSellingInProvinceGovernmentalRemainWeight, totalCommitmentSellingInProvinceFreeWeight: $totalCommitmentSellingInProvinceFreeWeight, totalCommitmentSellingInProvinceFreeRemainWeight: $totalCommitmentSellingInProvinceFreeRemainWeight, posAllocatedWeight: $posAllocatedWeight, posGovernmentalAllocatedWeight: $posGovernmentalAllocatedWeight, posFreeAllocatedWeight: $posFreeAllocatedWeight, wareHouseArchiveGovernmentalWeight: $wareHouseArchiveGovernmentalWeight, wareHouseArchiveFreeWeight: $wareHouseArchiveFreeWeight)';
}
}
/// @nodoc
abstract mixin class _$KillHouseSalesInfoDashboardCopyWith<$Res> implements $KillHouseSalesInfoDashboardCopyWith<$Res> {
factory _$KillHouseSalesInfoDashboardCopyWith(_KillHouseSalesInfoDashboard value, $Res Function(_KillHouseSalesInfoDashboard) _then) = __$KillHouseSalesInfoDashboardCopyWithImpl;
@override @useResult
$Res call({
double? totalGovernmentalInputWeight, double? totalFreeInputWeight, double? totalGovernmentalOutputWeight, double? totalFreeOutputWeight, double? totalGovernmentalRemainWeight, double? totalFreeRemainWeight,@JsonKey(name: 'total_kill_house_free_sale__bar_carcasses_weight') double? totalKillHouseFreeSaleBarCarcassesWeight, double? totalKillHouseAllocationsWeight, double? segmentationsWeight, double? coldHouseAllocationsWeight, double? totalSellingInProvinceGovernmentalWeight, double? totalSellingInProvinceFreeWeight, double? totalCommitmentSellingInProvinceGovernmentalWeight, double? totalCommitmentSellingInProvinceGovernmentalRemainWeight, double? totalCommitmentSellingInProvinceFreeWeight, double? totalCommitmentSellingInProvinceFreeRemainWeight, double? posAllocatedWeight, double? posGovernmentalAllocatedWeight, double? posFreeAllocatedWeight, double? wareHouseArchiveGovernmentalWeight, double? wareHouseArchiveFreeWeight
});
}
/// @nodoc
class __$KillHouseSalesInfoDashboardCopyWithImpl<$Res>
implements _$KillHouseSalesInfoDashboardCopyWith<$Res> {
__$KillHouseSalesInfoDashboardCopyWithImpl(this._self, this._then);
final _KillHouseSalesInfoDashboard _self;
final $Res Function(_KillHouseSalesInfoDashboard) _then;
/// Create a copy of KillHouseSalesInfoDashboard
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? totalGovernmentalInputWeight = freezed,Object? totalFreeInputWeight = freezed,Object? totalGovernmentalOutputWeight = freezed,Object? totalFreeOutputWeight = freezed,Object? totalGovernmentalRemainWeight = freezed,Object? totalFreeRemainWeight = freezed,Object? totalKillHouseFreeSaleBarCarcassesWeight = freezed,Object? totalKillHouseAllocationsWeight = freezed,Object? segmentationsWeight = freezed,Object? coldHouseAllocationsWeight = freezed,Object? totalSellingInProvinceGovernmentalWeight = freezed,Object? totalSellingInProvinceFreeWeight = freezed,Object? totalCommitmentSellingInProvinceGovernmentalWeight = freezed,Object? totalCommitmentSellingInProvinceGovernmentalRemainWeight = freezed,Object? totalCommitmentSellingInProvinceFreeWeight = freezed,Object? totalCommitmentSellingInProvinceFreeRemainWeight = freezed,Object? posAllocatedWeight = freezed,Object? posGovernmentalAllocatedWeight = freezed,Object? posFreeAllocatedWeight = freezed,Object? wareHouseArchiveGovernmentalWeight = freezed,Object? wareHouseArchiveFreeWeight = freezed,}) {
return _then(_KillHouseSalesInfoDashboard(
totalGovernmentalInputWeight: freezed == totalGovernmentalInputWeight ? _self.totalGovernmentalInputWeight : totalGovernmentalInputWeight // ignore: cast_nullable_to_non_nullable
as double?,totalFreeInputWeight: freezed == totalFreeInputWeight ? _self.totalFreeInputWeight : totalFreeInputWeight // ignore: cast_nullable_to_non_nullable
as double?,totalGovernmentalOutputWeight: freezed == totalGovernmentalOutputWeight ? _self.totalGovernmentalOutputWeight : totalGovernmentalOutputWeight // ignore: cast_nullable_to_non_nullable
as double?,totalFreeOutputWeight: freezed == totalFreeOutputWeight ? _self.totalFreeOutputWeight : totalFreeOutputWeight // ignore: cast_nullable_to_non_nullable
as double?,totalGovernmentalRemainWeight: freezed == totalGovernmentalRemainWeight ? _self.totalGovernmentalRemainWeight : totalGovernmentalRemainWeight // ignore: cast_nullable_to_non_nullable
as double?,totalFreeRemainWeight: freezed == totalFreeRemainWeight ? _self.totalFreeRemainWeight : totalFreeRemainWeight // ignore: cast_nullable_to_non_nullable
as double?,totalKillHouseFreeSaleBarCarcassesWeight: freezed == totalKillHouseFreeSaleBarCarcassesWeight ? _self.totalKillHouseFreeSaleBarCarcassesWeight : totalKillHouseFreeSaleBarCarcassesWeight // ignore: cast_nullable_to_non_nullable
as double?,totalKillHouseAllocationsWeight: freezed == totalKillHouseAllocationsWeight ? _self.totalKillHouseAllocationsWeight : totalKillHouseAllocationsWeight // ignore: cast_nullable_to_non_nullable
as double?,segmentationsWeight: freezed == segmentationsWeight ? _self.segmentationsWeight : segmentationsWeight // ignore: cast_nullable_to_non_nullable
as double?,coldHouseAllocationsWeight: freezed == coldHouseAllocationsWeight ? _self.coldHouseAllocationsWeight : coldHouseAllocationsWeight // ignore: cast_nullable_to_non_nullable
as double?,totalSellingInProvinceGovernmentalWeight: freezed == totalSellingInProvinceGovernmentalWeight ? _self.totalSellingInProvinceGovernmentalWeight : totalSellingInProvinceGovernmentalWeight // ignore: cast_nullable_to_non_nullable
as double?,totalSellingInProvinceFreeWeight: freezed == totalSellingInProvinceFreeWeight ? _self.totalSellingInProvinceFreeWeight : totalSellingInProvinceFreeWeight // ignore: cast_nullable_to_non_nullable
as double?,totalCommitmentSellingInProvinceGovernmentalWeight: freezed == totalCommitmentSellingInProvinceGovernmentalWeight ? _self.totalCommitmentSellingInProvinceGovernmentalWeight : totalCommitmentSellingInProvinceGovernmentalWeight // ignore: cast_nullable_to_non_nullable
as double?,totalCommitmentSellingInProvinceGovernmentalRemainWeight: freezed == totalCommitmentSellingInProvinceGovernmentalRemainWeight ? _self.totalCommitmentSellingInProvinceGovernmentalRemainWeight : totalCommitmentSellingInProvinceGovernmentalRemainWeight // ignore: cast_nullable_to_non_nullable
as double?,totalCommitmentSellingInProvinceFreeWeight: freezed == totalCommitmentSellingInProvinceFreeWeight ? _self.totalCommitmentSellingInProvinceFreeWeight : totalCommitmentSellingInProvinceFreeWeight // ignore: cast_nullable_to_non_nullable
as double?,totalCommitmentSellingInProvinceFreeRemainWeight: freezed == totalCommitmentSellingInProvinceFreeRemainWeight ? _self.totalCommitmentSellingInProvinceFreeRemainWeight : totalCommitmentSellingInProvinceFreeRemainWeight // ignore: cast_nullable_to_non_nullable
as double?,posAllocatedWeight: freezed == posAllocatedWeight ? _self.posAllocatedWeight : posAllocatedWeight // ignore: cast_nullable_to_non_nullable
as double?,posGovernmentalAllocatedWeight: freezed == posGovernmentalAllocatedWeight ? _self.posGovernmentalAllocatedWeight : posGovernmentalAllocatedWeight // ignore: cast_nullable_to_non_nullable
as double?,posFreeAllocatedWeight: freezed == posFreeAllocatedWeight ? _self.posFreeAllocatedWeight : posFreeAllocatedWeight // ignore: cast_nullable_to_non_nullable
as double?,wareHouseArchiveGovernmentalWeight: freezed == wareHouseArchiveGovernmentalWeight ? _self.wareHouseArchiveGovernmentalWeight : wareHouseArchiveGovernmentalWeight // ignore: cast_nullable_to_non_nullable
as double?,wareHouseArchiveFreeWeight: freezed == wareHouseArchiveFreeWeight ? _self.wareHouseArchiveFreeWeight : wareHouseArchiveFreeWeight // ignore: cast_nullable_to_non_nullable
as double?,
));
}
}
// dart format on

View File

@@ -0,0 +1,91 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'kill_house_sales_info_dashboard.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_KillHouseSalesInfoDashboard _$KillHouseSalesInfoDashboardFromJson(
Map<String, dynamic> json,
) => _KillHouseSalesInfoDashboard(
totalGovernmentalInputWeight:
(json['total_governmental_input_weight'] as num?)?.toDouble(),
totalFreeInputWeight: (json['total_free_input_weight'] as num?)?.toDouble(),
totalGovernmentalOutputWeight:
(json['total_governmental_output_weight'] as num?)?.toDouble(),
totalFreeOutputWeight: (json['total_free_output_weight'] as num?)?.toDouble(),
totalGovernmentalRemainWeight:
(json['total_governmental_remain_weight'] as num?)?.toDouble(),
totalFreeRemainWeight: (json['total_free_remain_weight'] as num?)?.toDouble(),
totalKillHouseFreeSaleBarCarcassesWeight:
(json['total_kill_house_free_sale__bar_carcasses_weight'] as num?)
?.toDouble(),
totalKillHouseAllocationsWeight:
(json['total_kill_house_allocations_weight'] as num?)?.toDouble(),
segmentationsWeight: (json['segmentations_weight'] as num?)?.toDouble(),
coldHouseAllocationsWeight: (json['cold_house_allocations_weight'] as num?)
?.toDouble(),
totalSellingInProvinceGovernmentalWeight:
(json['total_selling_in_province_governmental_weight'] as num?)
?.toDouble(),
totalSellingInProvinceFreeWeight:
(json['total_selling_in_province_free_weight'] as num?)?.toDouble(),
totalCommitmentSellingInProvinceGovernmentalWeight:
(json['total_commitment_selling_in_province_governmental_weight'] as num?)
?.toDouble(),
totalCommitmentSellingInProvinceGovernmentalRemainWeight:
(json['total_commitment_selling_in_province_governmental_remain_weight']
as num?)
?.toDouble(),
totalCommitmentSellingInProvinceFreeWeight:
(json['total_commitment_selling_in_province_free_weight'] as num?)
?.toDouble(),
totalCommitmentSellingInProvinceFreeRemainWeight:
(json['total_commitment_selling_in_province_free_remain_weight'] as num?)
?.toDouble(),
posAllocatedWeight: (json['pos_allocated_weight'] as num?)?.toDouble(),
posGovernmentalAllocatedWeight:
(json['pos_governmental_allocated_weight'] as num?)?.toDouble(),
posFreeAllocatedWeight: (json['pos_free_allocated_weight'] as num?)
?.toDouble(),
wareHouseArchiveGovernmentalWeight:
(json['ware_house_archive_governmental_weight'] as num?)?.toDouble(),
wareHouseArchiveFreeWeight: (json['ware_house_archive_free_weight'] as num?)
?.toDouble(),
);
Map<String, dynamic> _$KillHouseSalesInfoDashboardToJson(
_KillHouseSalesInfoDashboard instance,
) => <String, dynamic>{
'total_governmental_input_weight': instance.totalGovernmentalInputWeight,
'total_free_input_weight': instance.totalFreeInputWeight,
'total_governmental_output_weight': instance.totalGovernmentalOutputWeight,
'total_free_output_weight': instance.totalFreeOutputWeight,
'total_governmental_remain_weight': instance.totalGovernmentalRemainWeight,
'total_free_remain_weight': instance.totalFreeRemainWeight,
'total_kill_house_free_sale__bar_carcasses_weight':
instance.totalKillHouseFreeSaleBarCarcassesWeight,
'total_kill_house_allocations_weight':
instance.totalKillHouseAllocationsWeight,
'segmentations_weight': instance.segmentationsWeight,
'cold_house_allocations_weight': instance.coldHouseAllocationsWeight,
'total_selling_in_province_governmental_weight':
instance.totalSellingInProvinceGovernmentalWeight,
'total_selling_in_province_free_weight':
instance.totalSellingInProvinceFreeWeight,
'total_commitment_selling_in_province_governmental_weight':
instance.totalCommitmentSellingInProvinceGovernmentalWeight,
'total_commitment_selling_in_province_governmental_remain_weight':
instance.totalCommitmentSellingInProvinceGovernmentalRemainWeight,
'total_commitment_selling_in_province_free_weight':
instance.totalCommitmentSellingInProvinceFreeWeight,
'total_commitment_selling_in_province_free_remain_weight':
instance.totalCommitmentSellingInProvinceFreeRemainWeight,
'pos_allocated_weight': instance.posAllocatedWeight,
'pos_governmental_allocated_weight': instance.posGovernmentalAllocatedWeight,
'pos_free_allocated_weight': instance.posFreeAllocatedWeight,
'ware_house_archive_governmental_weight':
instance.wareHouseArchiveGovernmentalWeight,
'ware_house_archive_free_weight': instance.wareHouseArchiveFreeWeight,
};

View File

@@ -26,6 +26,8 @@ abstract class InventoryModel with _$InventoryModel {
int? totalGovernmentalCarcassesWeight,
int? totalFreeBarsCarcassesQuantity,
int? totalFreeBarsCarcassesWeight,
int? totalFreeRemainWeight,
int? totalGovernmentalRemainWeight,
double? weightAverage,
int? totalCarcassesQuantity,
int? totalCarcassesWeight,

File diff suppressed because one or more lines are too long

View File

@@ -43,6 +43,9 @@ _InventoryModel _$InventoryModelFromJson(
(json['total_free_bars_carcasses_quantity'] as num?)?.toInt(),
totalFreeBarsCarcassesWeight:
(json['total_free_bars_carcasses_weight'] as num?)?.toInt(),
totalFreeRemainWeight: (json['total_free_remain_weight'] as num?)?.toInt(),
totalGovernmentalRemainWeight:
(json['total_governmental_remain_weight'] as num?)?.toInt(),
weightAverage: (json['weight_average'] as num?)?.toDouble(),
totalCarcassesQuantity: (json['total_carcasses_quantity'] as num?)?.toInt(),
totalCarcassesWeight: (json['total_carcasses_weight'] as num?)?.toInt(),
@@ -101,6 +104,8 @@ Map<String, dynamic> _$InventoryModelToJson(
instance.totalGovernmentalCarcassesWeight,
'total_free_bars_carcasses_quantity': instance.totalFreeBarsCarcassesQuantity,
'total_free_bars_carcasses_weight': instance.totalFreeBarsCarcassesWeight,
'total_free_remain_weight': instance.totalFreeRemainWeight,
'total_governmental_remain_weight': instance.totalGovernmentalRemainWeight,
'weight_average': instance.weightAverage,
'total_carcasses_quantity': instance.totalCarcassesQuantity,
'total_carcasses_weight': instance.totalCarcassesWeight,

View File

@@ -32,9 +32,16 @@ abstract class ChickenRepository {
//region Remote
//region Steward
Future<List<InventoryModel>?> getInventory({required String token, CancelToken? cancelToken});
Future<List<InventoryModel>?> getInventory({
required String token,
required String role,
CancelToken? cancelToken,
});
Future<KillHouseDistributionInfo?> getKillHouseDistributionInfo({required String token});
Future<KillHouseDistributionInfo?> getKillHouseDistributionInfo({
required String token,
});
Future<BarInformation?> getGeneralBarInformation({
required String token,
@@ -46,7 +53,10 @@ abstract class ChickenRepository {
Map<String, dynamic>? queryParameters,
});
Future<void> setSateForArrivals({required String token, required Map<String, dynamic> request});
Future<void> setSateForArrivals({
required String token,
required Map<String, dynamic> request,
});
Future<PaginationModel<ImportedLoadsModel>?> getImportedLoadsModel({
required String token,
@@ -58,9 +68,15 @@ abstract class ChickenRepository {
Map<String, dynamic>? queryParameters,
});
Future<void> confirmAllocation({required String token, required Map<String, dynamic> allocation});
Future<void> confirmAllocation({
required String token,
required Map<String, dynamic> allocation,
});
Future<void> denyAllocation({required String token, required String allocationToken});
Future<void> denyAllocation({
required String token,
required String allocationToken,
});
Future<void> confirmAllAllocation({
required String token,
@@ -86,7 +102,10 @@ abstract class ChickenRepository {
Map<String, dynamic>? queryParameters,
});
Future<void> updateStewardAllocation({required String token, required ConformAllocation request});
Future<void> updateStewardAllocation({
required String token,
required ConformAllocation request,
});
Future<StewardFreeBarDashboard?> getStewardDashboard({
required String token,
@@ -100,7 +119,8 @@ abstract class ChickenRepository {
required String endDate,
});
Future<PaginationModel<StewardFreeBar>?> getStewardPurchasesOutSideOfTheProvince({
Future<PaginationModel<StewardFreeBar>?>
getStewardPurchasesOutSideOfTheProvince({
required String token,
Map<String, dynamic>? queryParameters,
});
@@ -110,20 +130,18 @@ abstract class ChickenRepository {
required CreateStewardFreeBar body,
});
Future<CreateStewardFreeBar?> editStewardPurchasesOutSideOfTheProvince({
required String token,
required CreateStewardFreeBar body,
});
Future<void> deleteStewardPurchasesOutSideOfTheProvince({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<PaginationModel<OutProvinceCarcassesBuyer>?> getOutProvinceCarcassesBuyer({
Future<PaginationModel<OutProvinceCarcassesBuyer>?>
getOutProvinceCarcassesBuyer({
required String token,
Map<String, dynamic>? queryParameters,
});
@@ -154,27 +172,40 @@ abstract class ChickenRepository {
Future<void> deleteOutProvinceStewardFreeBar({
required String token,
required String key
required String key,
});
Future<UserProfile?> getUserProfile({required String token});
Future<void> updateUserProfile({required String token, required UserProfile userProfile});
Future<void> updateUserProfile({
required String token,
required UserProfile userProfile,
});
Future<void> updatePassword({required String token, required ChangePasswordRequestModel model});
Future<void> updatePassword({
required String token,
required ChangePasswordRequestModel model,
});
Future<PaginationModel<SegmentationModel>?> getSegmentation({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> createSegmentation({required String token, required SegmentationModel model});
Future<void> createSegmentation({
required String token,
required SegmentationModel model,
});
Future<void> editSegmentation({required String token, required SegmentationModel model});
Future<void> editSegmentation({
required String token,
required SegmentationModel model,
});
Future<SegmentationModel?> deleteSegmentation({required String token, required String key});
Future<SegmentationModel?> deleteSegmentation({
required String token,
required String key,
});
Future<BroadcastPrice?> getBroadcastPrice({required String token});
@@ -187,9 +218,6 @@ abstract class ChickenRepository {
//endregion
//endregion
//region local

View File

@@ -41,12 +41,14 @@ class ChickenRepositoryImp implements ChickenRepository {
@override
Future<List<InventoryModel>?> getInventory({
required String token,
required String role,
CancelToken? cancelToken,
}) async {
var res = await remote.getInventory(token: token, cancelToken: cancelToken);
var res = await remote.getInventory(token: token, role: role, cancelToken: cancelToken);
return res;
}
@override
Future<KillHouseDistributionInfo?> getKillHouseDistributionInfo({
required String token,

View File

@@ -4,8 +4,11 @@ import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_request_list/kill_request_list.dart'
as listModel
show KillRequestList;
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_sales_info_dashboard.dart';
import 'package:rasadyar_core/core.dart';
abstract class KillHouseRepository {
//region requestKill
Future<List<KillHouseResponse>?> getKillHouseList({
required String token,
Map<String, dynamic>? queryParameters,
@@ -16,12 +19,29 @@ abstract class KillHouseRepository {
Map<String, dynamic>? queryParameters,
});
Future<void> submitKillHouseRequest({required String token, required KillRequestResponse data});
Future<void> submitKillHouseRequest({
required String token,
required KillRequestResponse data,
});
Future<List<listModel.KillRequestList>?> getListKillRequest({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> deleteKillRequest({required String token, required int requestId});
Future<void> deleteKillRequest({
required String token,
required int requestId,
});
//endregion
//region warehouseAndDistribution
Future<KillHouseSalesInfoDashboard?> getKillHouseSalesInfoDashboard({
required String token,
CancelToken? cancelToken,
Map<String, dynamic>? queryParameters,
});
//endregion
}

View File

@@ -4,6 +4,8 @@ import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_house/kill_house_response.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_request_list/kill_request_list.dart'
as listModel;
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_sales_info_dashboard.dart';
import 'package:rasadyar_core/core.dart';
import 'kill_house_repository.dart';
@@ -17,7 +19,10 @@ class KillHouseRepositoryImpl extends KillHouseRepository {
required String token,
Map<String, dynamic>? queryParameters,
}) async {
return await remoteDataSource.getKillHouseList(token: token, queryParameters: queryParameters);
return await remoteDataSource.getKillHouseList(
token: token,
queryParameters: queryParameters,
);
}
@override
@@ -37,7 +42,10 @@ class KillHouseRepositoryImpl extends KillHouseRepository {
required KillRequestResponse data,
}) async {
var jsonData = data.toJson();
return await remoteDataSource.submitKillHouseRequest(token: token, data: jsonData);
return await remoteDataSource.submitKillHouseRequest(
token: token,
data: jsonData,
);
}
@override
@@ -52,7 +60,31 @@ class KillHouseRepositoryImpl extends KillHouseRepository {
}
@override
Future<void> deleteKillRequest({required String token, required int requestId}) async {
await remoteDataSource.deleteKillRequest(token: token, requestId: requestId);
Future<void> deleteKillRequest({
required String token,
required int requestId,
}) async {
await remoteDataSource.deleteKillRequest(
token: token,
requestId: requestId,
);
}
//endregion
//region warehouseAndDistribution
@override
Future<KillHouseSalesInfoDashboard?> getKillHouseSalesInfoDashboard({
required String token,
CancelToken? cancelToken,
Map<String, dynamic>? queryParameters,
}) async {
return await remoteDataSource.getKillHouseSalesInfoDashboard(
token: token,
cancelToken: cancelToken,
queryParameters: queryParameters,
);
}
//endregion
}

View File

@@ -1,4 +1,5 @@
import 'package:rasadyar_chicken/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_core/core.dart';
class KillHouseActionLogic extends GetxController {
@@ -7,19 +8,28 @@ class KillHouseActionLogic extends GetxController {
title: "ثبت درخواست",
icon: Assets.vec.submitRequestSvg.path,
route: ChickenRoutes.submitRequestKillHouse,
navId: killHouseActionKey,
),
GlassMorphismCardItem(
title: "انبار و توزیع",
icon: Assets.vec.warehouseDistributionSvg.path,
route: '',
route: ChickenRoutes.initWarehouseAndDistribution,
),
GlassMorphismCardItem(
title: "سفارشات دریافتی",
icon: Assets.vec.ordersReceivedSvg.path,
route: '',
),
GlassMorphismCardItem(title: "خرید مستقیم", icon: Assets.vec.directPurchaseSvg.path, route: ''),
GlassMorphismCardItem(title: "تخصیص خودرو", icon: Assets.vec.carAllocationSvg.path, route: ''),
GlassMorphismCardItem(
title: "خرید مستقیم",
icon: Assets.vec.directPurchaseSvg.path,
route: '',
),
GlassMorphismCardItem(
title: "تخصیص خودرو",
icon: Assets.vec.carAllocationSvg.path,
route: '',
),
GlassMorphismCardItem(
title: "ورود اطلاعات بار",
icon: Assets.vec.enterCargoInformationSvg.path,

View File

@@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_core/core.dart';
@@ -15,7 +14,7 @@ class KillHouseActionPage extends GetView<KillHouseActionLogic> {
child: GlassMorphismGrid(
items: controller.items,
onTap: (item) {
Get.toNamed(item.route, id: killHouseActionKey);
Get.toNamed(item.route, id: item.navId);
},
),
);

View File

@@ -0,0 +1,36 @@
import 'package:flutter/services.dart';
import 'package:rasadyar_core/core.dart';
class WarehouseAndDistributionBuyLogic extends GetxController {
List<String> routesName = ['خرید'];
DateTime? _lastBackPressed;
@override
void onReady() {
fLog('BuyLogic onReady');
super.onReady();
}
@override
void onClose() {
// TODO: implement onClose
super.onClose();
}
void onPopScopTaped() async {
final now = DateTime.now();
if (_lastBackPressed == null || now.difference(_lastBackPressed!) > Duration(seconds: 2)) {
_lastBackPressed = now;
Get.snackbar(
'خروج از برنامه',
'برای خروج دوباره بازگشت را بزنید',
snackPosition: SnackPosition.TOP,
duration: Duration(seconds: 2),
backgroundColor: AppColor.warning,
);
} else {
await SystemNavigator.pop();
}
}
}

View File

@@ -0,0 +1,62 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class WarehouseAndDistributionBuyPage
extends GetView<WarehouseAndDistributionBuyLogic> {
const WarehouseAndDistributionBuyPage({super.key});
@override
Widget build(BuildContext context) {
return ChickenBasePage(
routes: controller.routesName,
isBase: true,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 21.w,
children: [
GlassMorphismCardIcon(
title: 'خرید داخل استان',
vecIcon: Assets.vec.map1Svg.path,
gradient: LinearGradient(
colors: [Color(0xFF00E096), Color(0xFF007D5E)],
stops: [0.0, 0.95],
begin: AlignmentGeometry.topLeft,
end: AlignmentGeometry.bottomRight,
),
onTap: () {
Get.toNamed(
ChickenRoutes.buysInProvinceWarehouseAndDistribution,
id: killHouseWarehouseAndDistributionBuyKey,
);
},
),
GlassMorphismCardIcon(
title: 'خرید خارج استان',
vecIcon: Assets.vec.buyOutProvinceSvg.path,
gradient: LinearGradient(
colors: [Color(0xFF00E096), Color(0xFF007D5E)],
stops: [0.0, 0.95],
begin: AlignmentGeometry.topLeft,
end: AlignmentGeometry.bottomRight,
),
onTap: () {
Get.toNamed(
ChickenRoutes.buysOutOfProvinceWarehouseAndDistribution,
id: killHouseWarehouseAndDistributionBuyKey,
);
},
),
],
),
],
),
);
}
}

View File

@@ -0,0 +1,89 @@
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/buy/logic.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/buy_in_province_all/logic.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/buy_in_province_waiting/logic.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/root/logic.dart';
import 'package:rasadyar_core/core.dart';
class WarehouseAndDistributionBuyInProvinceLogic extends GetxController {
RxList<String> routesName = RxList();
RxList<int> isExpandedList = <int>[].obs;
RxnString searchedValue = RxnString();
Rx<Jalali> fromDateFilter = Jalali.now().obs;
Rx<Jalali> toDateFilter = Jalali.now().obs;
WarehouseAndDistributionRootLogic rootLogic = Get.find<WarehouseAndDistributionRootLogic>();
WarehouseAndDistributionBuyLogic get buyLogic => Get.find<WarehouseAndDistributionBuyLogic>();
RxInt selectedSegmentIndex = 0.obs;
WarehouseAndDistributionBuyInProvinceAllLogic buyAllLogic = Get.find<WarehouseAndDistributionBuyInProvinceAllLogic>();
WarehouseAndDistributionBuyInProvinceWaitingLogic buyWaitingLogic = Get.find<WarehouseAndDistributionBuyInProvinceWaitingLogic>();
@override
void onInit() {
super.onInit();
routesName.value = [...buyLogic.routesName, 'داخل استان'].toList();
routesName.add(selectedSegmentIndex.value == 0 ? 'در انتظار' : 'کل خریدها');
ever(selectedSegmentIndex, (callback) {
routesName.removeLast();
routesName.add(callback == 0 ? 'در انتظار' : 'کل خریدها');
});
ever(fromDateFilter, (callback) => _setFromDateFilter(callback));
ever(toDateFilter, (callback) => _setToDateFilter(callback));
}
@override
void onReady() {
fLog('BuyInProvinceLogic onReady');
super.onReady();
}
@override
void onClose() {
// TODO: implement onClose
super.onClose();
}
void _setFromDateFilter(Jalali jalali) {
final isWaiting = selectedSegmentIndex.value == 0;
if (isWaiting) {
buyWaitingLogic.fromDateFilter.value = fromDateFilter.value;
} else {
buyAllLogic.fromDateFilter.value = fromDateFilter.value;
}
}
void _setToDateFilter(Jalali jalali) {
final isWaiting = selectedSegmentIndex.value == 0;
if (isWaiting) {
buyWaitingLogic.toDateFilter.value = fromDateFilter.value;
} else {
buyAllLogic.toDateFilter.value = fromDateFilter.value;
}
}
Future<void> submitFilter() async {
final isWaiting = selectedSegmentIndex.value == 0;
if (isWaiting) {
buyWaitingLogic.getWaitingArrivals();
} else {
buyAllLogic.getAllArrivals();
}
}
void setSearchValue(String? data) {
searchedValue.value = data?.trim();
final isWaiting = selectedSegmentIndex.value == 0;
if (isWaiting) {
buyWaitingLogic.searchedValue.value = searchedValue.value;
} else {
buyAllLogic.searchedValue.value = searchedValue.value;
}
}
Future<void> onRefresh() async {
await rootLogic.onRefresh();
await Future.wait([buyWaitingLogic.getWaitingArrivals(), buyAllLogic.getAllArrivals()]);
}
}

View File

@@ -0,0 +1,115 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/buy_in_province_all/view.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/buy_in_province_waiting/view.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_chicken/presentation/widget/inventory/inventory_widget.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class WarehouseAndDistributionBuyInProvincePage
extends GetView<WarehouseAndDistributionBuyInProvinceLogic> {
const WarehouseAndDistributionBuyInProvincePage({super.key});
@override
Widget build(BuildContext context) {
return ChickenBasePage(
routesWidget: ContainerBreadcrumb(rxRoutes: controller.routesName),
onSearchChanged: (data) => controller.setSearchValue(data),
hasBack: true,
backId: killHouseWarehouseAndDistributionBuyKey,
onFilterTap: () {
Get.bottomSheet(filterBottomSheet());
},
onRefresh: controller.onRefresh,
child: Column(
spacing: 4.h,
children: [
ObxValue((data) {
return InventoryWidget(inventoryModel: data.value);
}, controller.rootLogic.inventoryModel),
segmentWidget(),
ObxValue((index) {
return Expanded(
child: index.value == 0
? WarehouseAndDistributionBuyInProvinceWaitingPage()
: WarehouseAndDistributionBuyInProvinceAllPage(),
);
}, controller.selectedSegmentIndex),
],
),
);
}
Padding segmentWidget() {
return Padding(
padding: const EdgeInsets.fromLTRB(8, 0, 8, 8),
child: Row(
children: [
Expanded(
child: RSegment(
children: ['وارد شده به انبار', 'کل خریدها'],
selectedIndex: 0,
borderColor: const Color(0xFFB4B4B4),
selectedBorderColor: AppColor.blueNormal,
selectedBackgroundColor: AppColor.blueLight,
onSegmentSelected: (index) =>
controller.selectedSegmentIndex.value = index,
backgroundColor: AppColor.whiteGreyNormal,
),
),
],
),
);
}
Widget filterBottomSheet() {
return BaseBottomSheet(
height: 200,
child: Column(
spacing: 16,
children: [
Text(
'فیلترها',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
Row(
spacing: 8,
children: [
Expanded(
child: dateFilterWidget(
date: controller.fromDateFilter,
onChanged: (jalali) =>
controller.fromDateFilter.value = jalali,
),
),
Expanded(
child: dateFilterWidget(
isFrom: false,
date: controller.toDateFilter,
onChanged: (jalali) => controller.toDateFilter.value = jalali,
),
),
],
),
RElevated(
text: 'اعمال فیلتر',
isFullWidth: true,
backgroundColor: AppColor.greenNormal,
onPressed: () {
controller.submitFilter();
Get.back();
},
height: 40,
),
SizedBox(height: 16),
],
),
);
}
}

View File

@@ -0,0 +1,180 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/request/steward_allocation/steward_allocation_request.dart';
import 'package:rasadyar_chicken/data/models/response/waiting_arrival/waiting_arrival.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/root/logic.dart';
import 'package:rasadyar_core/core.dart';
class WarehouseAndDistributionBuyInProvinceAllLogic extends GetxController {
RxInt isExpandedListIndex = (-1).obs;
Rx<Jalali> fromDateFilter = Jalali.now().obs;
Rx<Jalali> toDateFilter = Jalali.now().obs;
RxnString searchedValue = RxnString();
RxMap<String, bool> isLoadingConfirmMap = RxMap();
final RxBool isLoadingMoreAllocationsMade = false.obs;
RxInt currentPage = 1.obs;
WarehouseAndDistributionRootLogic rootLogic = Get.find<WarehouseAndDistributionRootLogic>();
Rx<Resource<PaginationModel<WaitingArrivalModel>>> allProduct =
Resource<PaginationModel<WaitingArrivalModel>>.loading().obs;
TextEditingController weightController = TextEditingController();
TextEditingController countController = TextEditingController();
TextEditingController lossController = TextEditingController();
TextEditingController approvedWithOtpController = TextEditingController();
RxBool approvedWithOtpCode = false.obs;
@override
void onInit() {
super.onInit();
getAllArrivals();
}
@override
void onReady() {
debounce(searchedValue, (callback) => getAllArrivals(), time: Duration(milliseconds: 2000));
super.onReady();
ever(approvedWithOtpCode, (callback) {
if (callback == false) {
approvedWithOtpController.clear();
}
});
}
Future<void> getAllArrivals([bool isLoadingMore = false]) async {
if (isLoadingMore) {
isLoadingMoreAllocationsMade.value = true;
} else {
allProduct.value = Resource<PaginationModel<WaitingArrivalModel>>.loading();
}
if (searchedValue.value != null &&
searchedValue.value!.trim().isNotEmpty &&
currentPage.value > 1) {
currentPage.value = 1;
}
safeCall(
call: () async => await rootLogic.chickenRepository.getWaitingArrivals(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildQueryParams(
queryParams: {'type': 'all'},
pageSize: 20,
page: currentPage.value,
search: 'filter',
role: 'Steward',
value: searchedValue.value,
fromDate: fromDateFilter.value.toDateTime(),
toDate: toDateFilter.value.toDateTime(),
),
),
onSuccess: (res) async {
await Future.delayed(Duration(milliseconds: 200));
if ((res?.count ?? 0) == 0) {
allProduct.value = Resource<PaginationModel<WaitingArrivalModel>>.empty();
} else {
allProduct.value = Resource<PaginationModel<WaitingArrivalModel>>.success(
PaginationModel<WaitingArrivalModel>(
count: res?.count ?? 0,
next: res?.next,
previous: res?.previous,
results: [...(allProduct.value.data?.results ?? []), ...(res?.results ?? [])],
),
);
}
},
);
}
Future<void> acceptEntries(WaitingArrivalModel model) async {
var request = StewardAllocationRequest(
allocationKey: model.key,
checkAllocation: true,
state: 'accepted',
receiverRealNumberOfCarcasses: model.realNumberOfCarcasses ?? 0,
receiverRealWeightOfCarcasses: model.realWeightOfCarcasses?.toInt() ?? 0,
registrationCode: approvedWithOtpCode.value
? int.parse(approvedWithOtpController.text)
: null,
weightLossOfCarcasses: model.weightLossOfCarcasses?.toInt() ?? 0,
).toJson();
request.removeWhere((key, value) => value == null);
safeCall(
showError: true,
call: () async => await rootLogic.chickenRepository.setSateForArrivals(
token: rootLogic.tokenService.accessToken.value!,
request: request,
),
onSuccess: (result) {
getAllArrivals();
rootLogic.onRefresh();
clearApprovedController();
toggleExpansion();
Get.back();
},
);
}
Future<void> denyEntries(WaitingArrivalModel model) async {
var request = StewardAllocationRequest(
allocationKey: model.key,
checkAllocation: true,
state: 'rejected',
).toJson();
request.removeWhere((key, value) => value == null);
safeCall(
call: () async => await rootLogic.chickenRepository.setSateForArrivals(
token: rootLogic.tokenService.accessToken.value!,
request: request,
),
onError: (error, stackTrace) {
eLog(error);
},
onSuccess: (result) {
getAllArrivals();
rootLogic.onRefresh();
},
);
}
String getVecPathItem(String? item) {
switch (item) {
case 'pending':
return Assets.vec.timerSvg.path;
case 'accepted':
return Assets.vec.checkSquareSvg.path;
case 'rejected':
return Assets.vec.closeCircleSvg.path;
default:
return Assets.vec.timerSvg.path;
}
}
void clearApprovedController() {
weightController.clear();
countController.clear();
lossController.clear();
approvedWithOtpController.clear();
approvedWithOtpCode.value = false;
}
void toggleExpansion({int? index}) {
if (isExpandedListIndex.value == index || index == null) {
isExpandedListIndex.value = -1;
} else {
isExpandedListIndex.value = index;
}
}
Color getLabelColor(String? receiverState) {
if (receiverState == 'pending') {
return AppColor.yellowNormal2;
}
return AppColor.mediumGreyDarkHover;
}
}

View File

@@ -0,0 +1,381 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rasadyar_chicken/data/models/response/waiting_arrival/waiting_arrival.dart';
import 'package:rasadyar_chicken/presentation/utils/string_utils.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class WarehouseAndDistributionBuyInProvinceAllPage extends GetView<WarehouseAndDistributionBuyInProvinceAllLogic> {
const WarehouseAndDistributionBuyInProvinceAllPage({super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: ObxValue((data) {
return RPaginatedListView(
listType: ListType.separated,
resource: data.value,
hasMore: data.value.data?.next != null,
padding: EdgeInsets.fromLTRB(8, 8, 8, 80),
itemBuilder: (context, index) {
var item = data.value.data!.results![index];
return ObxValue((val) {
return ExpandableListItem2(
selected: val.value == index,
onTap: () => controller.toggleExpansion(index: index),
index: index,
child: itemListWidget(item),
secondChild: itemListExpandedWidget(item),
labelColor: getLabelColor(item.receiverState),
labelIcon: controller.getVecPathItem(item.receiverState),
labelIconColor: controller.getLabelColor(item.receiverState),
);
}, controller.isExpandedListIndex);
},
itemCount: data.value.data?.results?.length ?? 0,
separatorBuilder: (context, index) => SizedBox(height: 8.h),
onLoadMore: () async => controller.getAllArrivals(true),
);
}, controller.allProduct),
);
}
Row itemListWidget(WaitingArrivalModel item) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(width: 20),
Expanded(
flex: 2,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 3,
children: [
Text(
item.toSteward?.user?.fullname ?? 'N/A',
textAlign: TextAlign.start,
style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal),
),
Text(
item.date?.formattedJalaliDate ?? 'N/A',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark),
),
],
),
),
Expanded(
flex: 3,
child: Column(
spacing: 3,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
spacing: 6,
children: [
Visibility(
visible: item.product?.name?.contains('مرغ گرم') ?? false,
child: Assets.vec.hotChickenSvg.svg(
width: 24,
height: 24,
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
),
),
Text(
item.weightOfCarcasses?.separatedByCommaFa.addKg ?? 'N/A',
textAlign: TextAlign.left,
textDirection: TextDirection.ltr,
style: AppFonts.yekan12Bold.copyWith(color: AppColor.blueNormal),
),
],
),
Text(
item.toSteward?.guildsName ?? 'N/Aaq',
textAlign: TextAlign.start,
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
),
],
),
),
Expanded(
flex: 1,
child: Assets.vec.scanSvg.svg(
width: 32.w,
height: 32.h,
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
),
),
],
);
}
Container itemListExpandedWidget(WaitingArrivalModel item) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)),
child: Column(
spacing: 8,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
item.toSteward?.user?.fullname ?? 'N/A',
textAlign: TextAlign.center,
style: AppFonts.yekan16.copyWith(color: AppColor.greenDark),
),
Spacer(),
Text(
item.receiverState?.faItem ?? 'N/A',
textAlign: TextAlign.center,
style: AppFonts.yekan10.copyWith(color: AppColor.darkGreyDark),
),
SizedBox(width: 7),
SvgGenImage.vec(controller.getVecPathItem(item.receiverState)).svg(
width: 16.w,
height: 16.h,
colorFilter: ColorFilter.mode(AppColor.darkGreyDark, BlendMode.srcIn),
),
],
),
Container(
height: 32,
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: ShapeDecoration(
color: AppColor.blueLight,
shape: RoundedRectangleBorder(
side: BorderSide(width: 1, color: AppColor.blueLightHover),
borderRadius: BorderRadius.circular(8),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
spacing: 3,
children: [
Text(
item.date?.toJalali.formatter.wN ?? 'N/A',
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
),
Text(
'${item.date?.toJalali.formatter.d} ${item.date?.toJalali.formatter.mN ?? 'N/A'}',
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
],
),
Text(
'${item.date?.toJalali.formatter.y}',
style: AppFonts.yekan20.copyWith(color: AppColor.textColor),
),
Text(
'${item.date?.toJalali.formatter.tHH}:${item.date?.toJalali.formatter.tMM ?? 'N/A'}',
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
),
],
),
),
buildRow(title: 'مشخصات فروشنده', value: item.toSteward?.user?.fullname ?? 'N/A'),
buildRow(
title: 'تلفن فروشنده',
value: item.toSteward?.user?.mobile ?? 'N/A',
valueStyle: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
buildRow(title: 'نوع تخصیص', value: item.allocationType?.faAllocationType ?? 'N/A'),
buildRow(title: ' سهمیه', value: item.quota?.faTitle ?? 'N/A'),
buildRow(title: 'محصول', value: item.product?.name ?? 'N/A'),
buildRow(
title: 'وزن خریداری شده',
value: item.weightOfCarcasses?.separatedByCommaFa ?? 'N/A',
valueLabel: 'کیلوگرم',
),
buildRow(
title: 'قیمت هر کیلوگرم',
titleLabel: (item.approvedPriceStatus ?? false) ? 'مصوب' : 'آزاد',
titleLabelStyle: AppFonts.yekan14Bold.copyWith(color: AppColor.greenNormal),
value: item.amount?.separatedByCommaFa ?? 'N/A',
valueLabel: 'ریال',
),
buildRow(
title: 'قیمت کل',
value: item.totalAmount?.separatedByCommaFa ?? 'N/A',
valueLabel: 'ریال',
),
Visibility(
visible: item.receiverState == 'pending',
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 16.w,
children: [
ObxValue((data) {
return RElevated(
text: 'تایید',
width: 150.w,
height: 40.h,
isLoading: data[item.key!] ?? false,
onPressed: () async {
await Get.bottomSheet(
conformationBottomSheet(item),
isScrollControlled: true,
).then((value) {
Get.back();
controller.clearApprovedController();
});
},
textStyle: AppFonts.yekan20.copyWith(color: Colors.white),
backgroundColor: AppColor.greenNormal,
);
}, controller.isLoadingConfirmMap),
ROutlinedElevated(
text: 'رد',
textStyle: AppFonts.yekan20.copyWith(color: AppColor.redNormal),
width: 150.w,
height: 40.h,
onPressed: () {
buildWarningDialog(
title: 'اخطار',
middleText: 'آیا از رد شدن این مورد اطمینان دارید؟',
onConfirm: () => controller.denyEntries(item),
onRefresh: () => controller.getAllArrivals(),
);
},
borderColor: AppColor.redNormal,
),
],
),
),
],
),
);
}
Color getLabelColor(String? item) {
switch (item) {
case 'pending':
return AppColor.blueLight;
case 'accepted':
return AppColor.greenLightHover;
case 'rejected':
return AppColor.redLightHover;
default:
return AppColor.blueLight;
}
}
Widget conformationBottomSheet(WaitingArrivalModel item) {
controller.weightController.text = item.weightOfCarcasses.separatedByComma;
return BaseBottomSheet(
height: 430.h,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
RTextField(
label: 'وزن(کیلوگرم)',
controller: controller.weightController,
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly, SeparatorInputFormatter()],
),
SizedBox(height: 16.h),
RTextField(
label: 'حجم(قطعه)',
controller: controller.countController,
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly, SeparatorInputFormatter()],
),
SizedBox(height: 16.h),
RTextField(
label: 'افت وزن(کیلوگرم)',
controller: controller.lossController,
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly, SeparatorInputFormatter()],
),
SizedBox(height: 16.h),
Text('تایید ', style: AppFonts.yekan16Bold.copyWith(color: AppColor.textColor)),
ObxValue((data) {
return Column(
children: [
RadioGroup(
groupValue: data.value,
onChanged: (value) {
controller.approvedWithOtpCode.value = value ?? false;
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
radioRow(
value: true,
label: ' با کد احراز',
onTap: () {
controller.approvedWithOtpCode.value = true;
},
),
radioRow(
value: false,
label: 'بدون کد احراز',
onTap: () {
controller.approvedWithOtpCode.value = false;
},
),
],
),
),
Visibility(
child: RTextField(
controller: controller.approvedWithOtpController,
label: 'کد احراز',
keyboardType: TextInputType.number,
),
visible: data.value,
),
],
);
}, controller.approvedWithOtpCode),
SizedBox(height: 30.h),
ObxValue((data) {
return RElevated(
enabled: controller.approvedWithOtpCode.value
? controller.approvedWithOtpController.text.isNotEmpty
: true,
text: 'تایید',
onPressed: () async {
await controller.acceptEntries(item);
},
isFullWidth: true,
);
}, controller.approvedWithOtpCode),
SizedBox(height: 20.h),
],
),
);
}
Widget radioRow({
required bool value,
required String label,
TextStyle? textStyle,
GestureTapCallback? onTap,
}) {
return GestureDetector(
onTap: onTap,
child: Row(
children: [
Radio(value: value),
Text(label, style: textStyle ?? AppFonts.yekan16.copyWith(color: AppColor.textColor)),
],
),
);
}
}

View File

@@ -0,0 +1,189 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/request/steward_allocation/steward_allocation_request.dart';
import 'package:rasadyar_chicken/data/models/response/waiting_arrival/waiting_arrival.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/root/logic.dart';
import 'package:rasadyar_chicken/presentation/utils/utils.dart';
import 'package:rasadyar_core/core.dart';
class WarehouseAndDistributionBuyInProvinceWaitingLogic extends GetxController {
RxInt isExpandedListIndex = (-1).obs;
Rx<Jalali> fromDateFilter = Jalali.now().obs;
Rx<Jalali> toDateFilter = Jalali.now().obs;
RxnString searchedValue = RxnString();
RxMap<String, bool> isLoadingConfirmMap = RxMap();
Rx<Color> bgConfirmAllColor = AppColor.blueNormal.obs;
RxInt currentPage = 1.obs;
final RxBool isLoadingMoreAllocationsMade = false.obs;
WarehouseAndDistributionRootLogic rootLogic = Get.find<WarehouseAndDistributionRootLogic>();
RxBool isButtonConfirm = false.obs;
Rx<Resource<PaginationModel<WaitingArrivalModel>>> waitingProduct =
Resource<PaginationModel<WaitingArrivalModel>>.loading().obs;
TextEditingController weightController = TextEditingController();
TextEditingController countController = TextEditingController();
TextEditingController lossController = TextEditingController();
TextEditingController approvedWithOtpController = TextEditingController();
RxBool approvedWithOtpCode = false.obs;
@override
void onInit() {
super.onInit();
debounce(
searchedValue,
(callback) => getWaitingArrivals(),
time: Duration(milliseconds: timeDebounce),
);
}
@override
void onReady() {
super.onReady();
getWaitingArrivals();
approvedWithOtpController.addListener(() {
isButtonConfirm.value = approvedWithOtpController.text.trim().length > 4;
});
}
void setSearchValue(String? data) {
searchedValue.value = data?.trim();
}
Future<void> getWaitingArrivals([bool isLoadingMore = false]) async {
if (isLoadingMore) {
isLoadingMoreAllocationsMade.value = true;
} else {
waitingProduct.value = Resource<PaginationModel<WaitingArrivalModel>>.loading();
}
if (searchedValue.value != null &&
searchedValue.value!.trim().isNotEmpty &&
currentPage.value > 1) {
currentPage.value = 1;
}
safeCall(
call: () async => await rootLogic.chickenRepository.getWaitingArrivals(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildQueryParams(
queryParams: {'type': 'not_entered'},
pageSize: 20,
page: currentPage.value,
search: 'filter',
role: 'Steward',
value: searchedValue.value,
fromDate: fromDateFilter.value.toDateTime(),
toDate: toDateFilter.value.toDateTime(),
),
),
onSuccess: (res) async {
await Future.delayed(Duration(milliseconds: 200));
if ((res?.count ?? 0) == 0) {
waitingProduct.value = Resource<PaginationModel<WaitingArrivalModel>>.empty();
} else {
waitingProduct.value = Resource<PaginationModel<WaitingArrivalModel>>.success(
PaginationModel<WaitingArrivalModel>(
count: res?.count ?? 0,
next: res?.next,
previous: res?.previous,
results: [...(waitingProduct.value.data?.results ?? []), ...(res?.results ?? [])],
),
);
flashingFabBgColor();
}
},
);
}
Future<void> acceptEntries(WaitingArrivalModel model) async {
var request = StewardAllocationRequest(
allocationKey: model.key,
checkAllocation: true,
state: 'accepted',
receiverRealNumberOfCarcasses: model.realNumberOfCarcasses ?? 0,
receiverRealWeightOfCarcasses: model.realWeightOfCarcasses?.toInt() ?? 0,
registrationCode: approvedWithOtpCode.value
? int.parse(approvedWithOtpController.text.trim())
: null,
weightLossOfCarcasses: model.weightLossOfCarcasses?.toInt() ?? 0,
stewardCheckAllocation: true,
).toJson();
request.removeWhere((key, value) => value == null);
safeCall(
showError: true,
showSuccess: true,
call: () async => await rootLogic.chickenRepository.setSateForArrivals(
token: rootLogic.tokenService.accessToken.value!,
request: request,
),
onError: (error, stackTrace) {
eLog(error);
},
onSuccess: (result) {
getWaitingArrivals();
rootLogic.onRefresh();
clearApprovedController();
toggleExpansion();
Future.delayed(Duration(seconds: 3), () {
Get.back();
Get.back();
});
},
);
}
Future<void> denyEntries(WaitingArrivalModel model) async {
var request = StewardAllocationRequest(
allocationKey: model.key,
checkAllocation: true,
state: 'rejected',
).toJson();
request.removeWhere((key, value) => value == null);
safeCall(
call: () async => await rootLogic.chickenRepository.setSateForArrivals(
token: rootLogic.tokenService.accessToken.value!,
request: request,
),
onError: (error, stackTrace) {
eLog(error);
},
onSuccess: (result) {
getWaitingArrivals();
rootLogic.onRefresh();
},
);
}
void flashingFabBgColor() {
Timer.periodic(Duration(seconds: 2), (timer) {
if (bgConfirmAllColor.value == AppColor.blueNormal) {
bgConfirmAllColor.value = AppColor.blueLightHover;
} else {
bgConfirmAllColor.value = AppColor.blueNormal;
}
});
}
void clearApprovedController() {
weightController.clear();
countController.clear();
lossController.clear();
approvedWithOtpController.clear();
approvedWithOtpCode.value = false;
}
void toggleExpansion({int? index}) {
if (isExpandedListIndex.value == index || index == null) {
isExpandedListIndex.value = -1;
} else {
isExpandedListIndex.value = index;
}
}
}

View File

@@ -0,0 +1,373 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rasadyar_chicken/data/models/response/waiting_arrival/waiting_arrival.dart';
import 'package:rasadyar_chicken/presentation/utils/string_utils.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class WarehouseAndDistributionBuyInProvinceWaitingPage extends GetView<WarehouseAndDistributionBuyInProvinceWaitingLogic> {
const WarehouseAndDistributionBuyInProvinceWaitingPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: ObxValue((data) {
return RPaginatedListView(
listType: ListType.separated,
resource: data.value,
hasMore: data.value.data?.next != null,
padding: EdgeInsets.fromLTRB(8, 8, 8, 80),
itemBuilder: (context, index) {
var item = data.value.data!.results![index];
return ObxValue((val) {
return ExpandableListItem2(
selected: controller.isExpandedListIndex.value == index,
onTap: () => controller.toggleExpansion(index: index),
index: index,
child: itemListWidget(item),
secondChild: itemListExpandedWidget(item),
labelColor: AppColor.blueLight,
labelIcon: Assets.vec.timerSvg.path,
labelIconColor: AppColor.yellowNormal2,
);
}, controller.isExpandedListIndex);
},
itemCount: data.value.data?.results?.length ?? 0,
separatorBuilder: (context, index) => SizedBox(height: 8.h),
onLoadMore: () async => controller.getWaitingArrivals(true),
);
}, controller.waitingProduct),
),
);
}
Row itemListWidget(WaitingArrivalModel item) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(width: 20),
Expanded(
flex: 2,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 3,
children: [
Text(
'${controller.rootLogic.isKillHouse(item) ? 'کشتارگاه' : 'مباشر'} ${controller.rootLogic.isKillHouse(item) ? item.killHouse?.name : item.steward?.user?.fullname} ',
textAlign: TextAlign.start,
overflow: TextOverflow.ellipsis,
style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal),
),
Text(
item.date?.formattedJalaliDate ?? 'ندارد',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark),
),
],
),
),
Expanded(
flex: 3,
child: Column(
spacing: 3,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
spacing: 6,
children: [
Visibility(
visible: item.product?.name?.contains('مرغ گرم') ?? false,
child: Assets.vec.hotChickenSvg.svg(
width: 24,
height: 24,
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
),
),
Text(
item.weightOfCarcasses?.separatedByCommaFa.addKg ?? 'ندارد',
textAlign: TextAlign.left,
textDirection: TextDirection.ltr,
style: AppFonts.yekan12Bold.copyWith(color: AppColor.blueNormal),
),
],
),
Text(
'${item.amount?.separatedByCommaFa} ریال',
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
),
],
),
),
Expanded(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 3,
children: [
Text(
(item.approvedPriceStatus ?? false) ? 'دولتی' : 'آزاد',
style: AppFonts.yekan12Bold.copyWith(
color: (item.approvedPriceStatus ?? false)
? AppColor.blueNormal
: AppColor.greenNormal,
),
),
],
),
),
],
);
}
Container itemListExpandedWidget(WaitingArrivalModel item) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)),
child: Column(
spacing: 8,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
'${controller.rootLogic.isKillHouse(item) ? item.killHouse?.name : item.steward?.user?.fullname} ',
textAlign: TextAlign.center,
style: AppFonts.yekan16.copyWith(color: AppColor.greenDark),
),
Spacer(),
Text(
'در انتظار',
textAlign: TextAlign.center,
style: AppFonts.yekan10.copyWith(color: AppColor.darkGreyDark),
),
SizedBox(width: 7),
Assets.vec.clockSvg.svg(width: 16.w, height: 16.h),
],
),
Container(
height: 32,
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: ShapeDecoration(
color: AppColor.blueLight,
shape: RoundedRectangleBorder(
side: BorderSide(width: 1, color: AppColor.blueLightHover),
borderRadius: BorderRadius.circular(8),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
spacing: 3,
children: [
Text(
item.date?.toJalali.formatter.wN ?? 'ندارد',
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
),
Text(
'${item.date?.toJalali.formatter.d} ${item.date?.toJalali.formatter.mN ?? 'ندارد'}',
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
],
),
Text(
'${item.date?.toJalali.formatter.y}',
style: AppFonts.yekan20.copyWith(color: AppColor.textColor),
),
Text(
'${item.date?.toJalali.formatter.tHH}:${item.date?.toJalali.formatter.tMM ?? 'ندارد'}',
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
),
],
),
),
buildRow(
title: 'مشخصات فروشنده',
value:
'${controller.rootLogic.isKillHouse(item) ? item.killHouse?.killHouseOperator?.user?.fullname : item.steward?.user?.fullname} ',
),
buildRow(
title: 'تلفن فروشنده',
value:
'${controller.rootLogic.isKillHouse(item) ? item.killHouse?.killHouseOperator?.user?.mobile : item.steward?.user?.mobile} ',
valueStyle: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
buildRow(title: 'نوع تخصیص', value: item.allocationType?.faAllocationType ?? 'ندارد'),
buildRow(title: ' سهمیه', value: item.quota?.faTitle ?? 'ندارد'),
buildRow(title: 'نوع فروش', value: item.saleType == "governmental" ? 'دولتی' : 'آزاد'),
buildRow(title: 'محصول', value: item.product?.name ?? 'ندارد'),
buildRow(
title: 'تاریخ تولید گوشت',
value: item.productionDate?.toJalali.toJalaliDateTime() ?? 'ندارد',
),
buildRow(
title: 'وزن خریداری شده',
value: '${item.weightOfCarcasses?.separatedByCommaFa} کیلوگرم',
),
buildRow(
title: 'قیمت هر کیلوگرم',
titleLabel: (item.approvedPriceStatus ?? false) ? 'دولتی' : 'آزاد',
titleLabelStyle: AppFonts.yekan14Bold.copyWith(color: AppColor.greenNormal),
value: '${item.amount?.separatedByCommaFa} ریال',
),
buildRow(title: 'قیمت کل', value: '${item.totalAmount?.separatedByCommaFa} ریال'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 16.w,
children: [
ObxValue((data) {
return RElevated(
text: 'تایید',
width: 150.w,
height: 40.h,
isLoading: data[item.key!] ?? false,
onPressed: () async {
await Get.bottomSheet(conformationBottomSheet(item), isScrollControlled: true);
},
textStyle: AppFonts.yekan20.copyWith(color: Colors.white),
backgroundColor: AppColor.greenNormal,
);
}, controller.isLoadingConfirmMap),
ROutlinedElevated(
text: 'رد',
textStyle: AppFonts.yekan20.copyWith(color: AppColor.redNormal),
width: 150.w,
height: 40.h,
onPressed: () {
buildWarningDialog(
title: 'اخطار',
middleText: 'آیا از رد شدن این مورد اطمینان دارید؟',
onConfirm: () => controller.denyEntries(item),
onRefresh: () => controller.getWaitingArrivals(),
);
},
borderColor: AppColor.redNormal,
),
],
),
],
),
);
}
Widget conformationBottomSheet(WaitingArrivalModel item) {
controller.weightController.text = item.weightOfCarcasses.separatedByComma;
return BaseBottomSheet(
height: 450.h,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 10),
RTextField(
label: 'وزن(کیلوگرم)',
controller: controller.weightController,
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly, SeparatorInputFormatter()],
),
SizedBox(height: 16.h),
RTextField(
label: 'حجم(قطعه)',
controller: controller.countController,
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly, SeparatorInputFormatter()],
),
SizedBox(height: 16.h),
RTextField(
label: 'افت وزن(کیلوگرم)',
controller: controller.lossController,
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly, SeparatorInputFormatter()],
),
SizedBox(height: 16.h),
Text('تایید ', style: AppFonts.yekan16Bold.copyWith(color: AppColor.textColor)),
ObxValue((data) {
return Column(
children: [
RadioGroup(
groupValue: data.value,
onChanged: (value) {
controller.approvedWithOtpCode.value = value ?? false;
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
radioRow(
value: true,
label: ' با کد احراز',
onTap: () {
controller.approvedWithOtpCode.value = true;
},
),
radioRow(
value: false,
label: 'بدون کد احراز',
onTap: () {
controller.approvedWithOtpCode.value = false;
},
),
],
),
),
Visibility(
child: RTextField(
controller: controller.approvedWithOtpController,
label: 'کد احراز',
keyboardType: TextInputType.number,
maxLength: 5,
),
visible: data.value,
),
],
);
}, controller.approvedWithOtpCode),
SizedBox(height: 30.h),
Obx(() {
return RElevated(
enabled: controller.approvedWithOtpCode.value
? controller.isButtonConfirm.value
: true,
text: 'تایید',
onPressed: () async {
await controller.acceptEntries(item);
},
isFullWidth: true,
);
}),
SizedBox(height: 20.h),
],
),
);
}
Widget radioRow({
required bool value,
required String label,
TextStyle? textStyle,
GestureTapCallback? onTap,
}) {
return GestureDetector(
onTap: onTap,
child: Row(
children: [
Radio(value: value),
Text(label, style: textStyle ?? AppFonts.yekan16.copyWith(color: AppColor.textColor)),
],
),
);
}
}

View File

@@ -0,0 +1,303 @@
import 'package:flutter/cupertino.dart';
import 'package:rasadyar_chicken/data/models/request/create_steward_free_bar/create_steward_free_bar.dart';
import 'package:rasadyar_chicken/data/models/response/iran_province_city/iran_province_city_model.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/data/models/response/steward_free_bar/steward_free_bar.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/buy/logic.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/root/logic.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/sale/logic.dart';
import 'package:rasadyar_chicken/presentation/utils/utils.dart';
import 'package:rasadyar_core/core.dart';
class WarehouseAndDistributionBuyOutOfProvinceLogic extends GetxController {
late List<String> routesName;
RxBool isSubmitButtonEnabled = false.obs;
RxInt expandedListIndex = (-1).obs;
final RxInt currentPage = 1.obs;
final RxBool isLoadingMoreAllocationsMade = false.obs;
final RxBool isOnLoadingSubmitOrEdit = false.obs;
//TODO add this to Di
ImagePicker imagePicker = ImagePicker();
Rx<Resource<PaginationModel<StewardFreeBar>>> purchaseOutOfProvinceList =
Resource<PaginationModel<StewardFreeBar>>.loading().obs;
Rxn<ProductModel> selectedProduct = Rxn();
RxList<IranProvinceCityModel> cites = <IranProvinceCityModel>[].obs;
Rxn<IranProvinceCityModel> selectedProvince = Rxn();
Rxn<IranProvinceCityModel> selectedCity = Rxn();
Rxn<XFile> selectedImage = Rxn<XFile>();
final RxnString _base64Image = RxnString();
RxnString editImageUrl = RxnString();
RxnString editFreeBarKey = RxnString();
WarehouseAndDistributionRootLogic rootLogic = Get.find<WarehouseAndDistributionRootLogic>();
WarehouseAndDistributionBuyLogic buyLogic = Get.find<WarehouseAndDistributionBuyLogic>();
WarehouseAndDistributionSaleLogic outOfTheProvinceLogic = Get.find<WarehouseAndDistributionSaleLogic>();
GlobalKey<FormState> formKey = GlobalKey<FormState>();
TextEditingController sellerNameController = TextEditingController();
TextEditingController sellerPhoneController = TextEditingController();
TextEditingController carcassWeightController = TextEditingController();
TextEditingController carcassCountController = TextEditingController();
Rx<Jalali> fromDateFilter = Jalali.now().obs;
Rx<Jalali> toDateFilter = Jalali.now().obs;
RxnString searchedValue = RxnString();
@override
void onInit() {
super.onInit();
routesName = [...buyLogic.routesName, 'خارج استان'].toList();
}
@override
void onReady() {
super.onReady();
getStewardPurchaseOutOfProvince();
selectedProvince.listen((p0) => getCites());
selectedProduct.value = rootLogic.rolesProductsModel.first;
setupListeners();
debounce(
searchedValue,
(callback) => getStewardPurchaseOutOfProvince(),
time: Duration(milliseconds: timeDebounce),
);
}
@override
void onClose() {
sellerNameController.dispose();
sellerPhoneController.dispose();
carcassWeightController.dispose();
super.onClose();
}
void setSearchValue(String? data) {
searchedValue.value = data?.trim();
}
Future<void> getStewardPurchaseOutOfProvince([bool isLoadingMore = false]) async {
if (isLoadingMore) {
isLoadingMoreAllocationsMade.value = true;
} else {
purchaseOutOfProvinceList.value = Resource<PaginationModel<StewardFreeBar>>.loading();
}
if (searchedValue.value != null &&
searchedValue.value!.trim().isNotEmpty &&
currentPage.value > 1) {
currentPage.value = 1; // Reset to first page if search value is set
}
await safeCall(
call: () => rootLogic.chickenRepository.getStewardPurchasesOutSideOfTheProvince(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildQueryParams(
pageSize: 20,
page: currentPage.value,
search: 'filter',
role: 'Steward',
value: searchedValue.value,
fromDate: fromDateFilter.value.toDateTime(),
toDate: toDateFilter.value.toDateTime(),
),
),
onSuccess: (res) async {
await Future.delayed(Duration(milliseconds: 500));
if ((res?.count ?? 0) == 0) {
purchaseOutOfProvinceList.value = Resource<PaginationModel<StewardFreeBar>>.empty();
} else {
purchaseOutOfProvinceList.value = Resource<PaginationModel<StewardFreeBar>>.success(
PaginationModel<StewardFreeBar>(
count: res?.count ?? 0,
next: res?.next,
previous: res?.previous,
results: [
...(purchaseOutOfProvinceList.value.data?.results ?? []),
...(res?.results ?? []),
],
),
);
}
},
);
}
Future<void> getCites() async {
await safeCall(
call: () =>
rootLogic.chickenRepository.getCity(provinceName: selectedProvince.value?.name ?? ''),
onSuccess: (result) {
if (result != null && result.isNotEmpty) {
cites.value = result;
}
},
);
}
void setupListeners() {
sellerNameController.addListener(() {
checkFormValid();
if (!isSubmitButtonEnabled.value) {
isSubmitButtonEnabled.value = !isSubmitButtonEnabled.value;
}
});
sellerPhoneController.addListener(checkFormValid);
carcassWeightController.addListener(checkFormValid);
carcassCountController.addListener(checkFormValid);
ever(selectedProvince, (_) => checkFormValid());
ever(selectedCity, (_) => checkFormValid());
ever(selectedProduct, (_) => checkFormValid());
ever(selectedImage, (data) async {
checkFormValid();
if (data?.path != null) {
_base64Image.value = await convertImageToBase64(data!.path);
}
});
}
void checkFormValid() {
isSubmitButtonEnabled.value =
sellerNameController.text.isNotEmpty &&
sellerPhoneController.text.isNotEmpty &&
carcassWeightController.text.isNotEmpty &&
carcassCountController.text.isNotEmpty &&
selectedProvince.value != null &&
selectedCity.value != null &&
selectedProduct.value != null &&
(selectedImage.value != null || editImageUrl.value != null);
if (isSubmitButtonEnabled.value) {
isOnLoadingSubmitOrEdit.value = false;
}
}
Future<bool> createStewardPurchaseOutOfProvince() async {
bool res = false;
isOnLoadingSubmitOrEdit.value = true;
if (!(formKey.currentState?.validate() ?? false)) {
isOnLoadingSubmitOrEdit.value = false;
return res;
}
await safeCall(
showError: true,
call: () async {
CreateStewardFreeBar createStewardFreeBar = CreateStewardFreeBar(
productKey: selectedProduct.value!.key,
killHouseName: sellerNameController.text,
killHouseMobile: sellerPhoneController.text,
province: selectedProvince.value!.name,
city: selectedCity.value!.name,
weightOfCarcasses: int.parse(carcassWeightController.text.clearComma),
numberOfCarcasses: int.parse(carcassCountController.text.clearComma),
barImage: _base64Image.value,
date: DateTime.now().formattedYHMS,
);
await rootLogic.chickenRepository.createStewardPurchasesOutSideOfTheProvince(
token: rootLogic.tokenService.accessToken.value!,
body: createStewardFreeBar,
);
},
onSuccess: (result) {
getStewardPurchaseOutOfProvince();
resetSubmitForm();
toggleExpansion();
res = true;
},
);
isOnLoadingSubmitOrEdit.value = false;
return res;
}
void resetSubmitForm() {
sellerNameController.clear();
sellerPhoneController.clear();
carcassWeightController.clear();
carcassCountController.clear();
selectedProvince.value = null;
selectedCity.value = null;
selectedImage.value = null;
_base64Image.value = null;
editImageUrl.value = null;
isSubmitButtonEnabled.value = false;
}
void setEditData(StewardFreeBar item) async {
editImageUrl.value = item.barImage;
sellerNameController.text = item.killHouseName ?? '';
sellerPhoneController.text = item.killHouseMobile ?? '';
carcassWeightController.text = item.weightOfCarcasses.separatedByComma;
carcassCountController.text = item.numberOfCarcasses.separatedByComma;
editFreeBarKey.value = item.key;
selectedProvince.value = IranProvinceCityModel(name: item.province);
selectedCity.value = IranProvinceCityModel(name: item.city);
selectedProduct.value = rootLogic.rolesProductsModel.firstWhere(
(element) => element.key == item.product!.key,
);
isSubmitButtonEnabled.value = true;
}
Future<void> editStewardPurchaseOutOfProvince() async {
CreateStewardFreeBar edit = CreateStewardFreeBar(
productKey: selectedProduct.value!.key,
key: editFreeBarKey.value,
killHouseName: sellerNameController.text,
killHouseMobile: sellerPhoneController.text,
province: selectedProvince.value!.name,
city: selectedCity.value!.name,
weightOfCarcasses: int.parse(carcassWeightController.text.clearComma),
numberOfCarcasses: int.parse(carcassCountController.text.clearComma),
date: DateTime.now().formattedYHMS,
);
if (_base64Image.value != null) {
edit = edit.copyWith(barImage: _base64Image.value);
}
await safeCall(
showError: true,
call: () => rootLogic.chickenRepository.editStewardPurchasesOutSideOfTheProvince(
token: rootLogic.tokenService.accessToken.value!,
body: edit,
),
onSuccess: (result) {
onRefresh();
rootLogic.onRefresh();
toggleExpansion();
},
);
}
Future<void> deleteStewardPurchaseOutOfProvince(String key) async {
await safeCall(
call: () => rootLogic.chickenRepository.deleteStewardPurchasesOutSideOfTheProvince(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildRawQueryParams(queryParams: {'key': key}),
),
);
}
Future<void> onRefresh() async {
currentPage.value = 1;
await rootLogic.onRefresh();
await getStewardPurchaseOutOfProvince();
}
void toggleExpansion({int? index}) {
if (expandedListIndex.value == index || index == null) {
expandedListIndex.value = -1;
} else {
expandedListIndex.value = index;
}
}
}

View File

@@ -0,0 +1,698 @@
import 'dart:io';
import 'package:flutter/cupertino.dart' hide Image;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rasadyar_chicken/data/models/response/iran_province_city/iran_province_city_model.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/data/models/response/steward_free_bar/steward_free_bar.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class WarehouseAndDistributionBuyOutOfProvincePage
extends GetView<WarehouseAndDistributionBuyOutOfProvinceLogic> {
const WarehouseAndDistributionBuyOutOfProvincePage({super.key});
@override
Widget build(BuildContext context) {
return ChickenBasePage(
routes: controller.routesName,
backId: killHouseWarehouseAndDistributionBuyKey,
onRefresh: controller.onRefresh,
onSearchChanged: (data) => controller.setSearchValue(data),
onFilterTap: () {
Get.bottomSheet(filterBottomSheet());
},
child: Stack(
children: [
Positioned.fill(
child: Column(
children: [
//inventoryWidget(controller.rootLogic),
ObxValue((data) {
return RPaginatedListView(
listType: ListType.separated,
resource: data.value,
hasMore: data.value.data?.next != null,
padding: EdgeInsets.fromLTRB(8, 8, 8, 80),
itemBuilder: (context, index) {
var item = data.value.data!.results![index];
return ObxValue((val) {
return ExpandableListItem2(
selected: val.value == index,
onTap: () => controller.toggleExpansion(index: index),
index: index,
child: itemListWidget(item),
secondChild: itemListExpandedWidget(item),
labelColor: AppColor.blueLight,
labelIcon: Assets.vec.truckFastOutlinedSvg.path,
);
}, controller.expandedListIndex);
},
itemCount: data.value.data?.results?.length ?? 0,
separatorBuilder: (context, index) => SizedBox(height: 8.h),
onLoadMore: () async =>
controller.getStewardPurchaseOutOfProvince(true),
);
}, controller.purchaseOutOfProvinceList),
],
),
),
Positioned(
right: 5,
bottom: 95,
child: RFab.add(
onPressed: () {
Get.bottomSheet(
addPurchasedInformationBottomSheet(),
isScrollControlled: true,
ignoreSafeArea: false,
).whenComplete(() {
controller.resetSubmitForm();
});
},
),
),
],
),
);
}
Container itemListExpandedWidget(StewardFreeBar item) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Column(
spacing: 8,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
'${item.province}-${item.city}',
textAlign: TextAlign.center,
style: AppFonts.yekan16.copyWith(color: AppColor.greenDark),
),
],
),
Container(
height: 32,
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: ShapeDecoration(
color: AppColor.blueLight,
shape: RoundedRectangleBorder(
side: BorderSide(width: 1, color: AppColor.blueLightHover),
borderRadius: BorderRadius.circular(8),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
spacing: 3,
children: [
Text(
item.date?.toJalali.formatter.wN ?? 'ندارد',
style: AppFonts.yekan14.copyWith(
color: AppColor.textColor,
),
),
Text(
'${item.date?.toJalali.formatter.d} ${item.date?.toJalali.formatter.mN ?? 'ندارد'}',
style: AppFonts.yekan14.copyWith(
color: AppColor.blueNormal,
),
),
],
),
Text(
'${item.date?.toJalali.formatter.y}',
style: AppFonts.yekan20.copyWith(color: AppColor.textColor),
),
Text(
'${item.date?.toJalali.formatter.tHH}:${item.date?.toJalali.formatter.tMM ?? 'ندارد'}',
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
),
],
),
),
buildRow(
title: 'مشخصات فروشنده',
value: item.killHouseName ?? 'ندارد',
),
buildRow(
title: 'تلفن فروشنده',
value: item.killHouseMobile ?? 'ندارد',
valueStyle: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
buildRow(title: 'محصول', value: item.product?.name ?? 'ندارد'),
buildRow(
title: 'وزن خریداری شده',
value: '${item.weightOfCarcasses?.separatedByCommaFa} کیلوگرم',
),
buildRow(
title: 'حجم خریداری شده',
value: '${item.numberOfCarcasses?.separatedByCommaFa} قطعه',
),
buildRowOnTapped(
title: 'مشاهده بارنامه',
titleStyle: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
valueWidget: Assets.vec.clipboardEyeSvg.svg(
width: 20,
height: 24,
colorFilter: ColorFilter.mode(
AppColor.blueNormal,
BlendMode.srcIn,
),
),
onTap: () {
Get.bottomSheet(
BaseBottomSheet(
height: 400,
child: Column(
spacing: 16,
children: [
Text(
'بارنامه',
style: AppFonts.yekan16Bold.copyWith(
color: AppColor.blueNormal,
),
),
Image.network(
item.barImage ?? '',
fit: BoxFit.cover,
height: 300,
errorBuilder: (context, error, stackTrace) {
eLog(error.toString());
return Center(child: Text('خطایی پیش آمده!'));
},
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return CupertinoActivityIndicator();
},
),
],
),
),
);
},
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 16.w,
children: [
RElevated(
text: 'ویرایش',
width: 150.w,
height: 40.h,
onPressed: () {
controller.setEditData(item);
Get.bottomSheet(
addPurchasedInformationBottomSheet(true),
isScrollControlled: true,
).whenComplete(() {
controller.resetSubmitForm();
});
},
textStyle: AppFonts.yekan20.copyWith(color: Colors.white),
backgroundColor: AppColor.greenNormal,
),
ROutlinedElevated(
text: 'حذف',
textStyle: AppFonts.yekan20.copyWith(color: AppColor.redNormal),
width: 150.w,
height: 40.h,
onPressed: () {
buildDeleteDialog(
onConfirm: () => controller
.deleteStewardPurchaseOutOfProvince(item.key!),
onRefresh: () async {
controller.rootLogic.onRefresh();
controller.onRefresh();
controller.toggleExpansion();
},
);
},
borderColor: AppColor.redNormal,
),
],
),
],
),
);
}
Row itemListWidget(StewardFreeBar item) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(width: 20),
Expanded(
flex: 2,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 3,
children: [
Text(
item.killHouseName ?? 'ندارد',
textAlign: TextAlign.start,
style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal),
),
Text(
item.date?.formattedJalaliDate ?? 'ندارد',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark),
),
],
),
),
Expanded(
flex: 3,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
spacing: 3,
children: [
Visibility(
visible: item.product?.name?.contains('مرغ گرم') ?? false,
child: Assets.vec.hotChickenSvg.svg(
width: 24,
height: 24,
colorFilter: ColorFilter.mode(
AppColor.blueNormal,
BlendMode.srcIn,
),
),
),
Text(
'${item.weightOfCarcasses?.separatedByCommaFa}kg',
textAlign: TextAlign.left,
style: AppFonts.yekan12.copyWith(
color: AppColor.blueNormal,
),
),
],
),
SizedBox(height: 2),
Text(
'${item.numberOfCarcasses.separatedByComma} ${'قطعه'}',
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
),
],
),
),
Expanded(
flex: 2,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 3,
children: [
Text(
'${item.province}',
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal),
),
Text(
'${item.city}',
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
),
],
),
),
],
);
}
Widget addPurchasedInformationBottomSheet([bool isOnEdit = false]) {
return BaseBottomSheet(
child: Form(
key: controller.formKey,
child: Column(
spacing: 8,
children: [
Text(
isOnEdit ? 'ویرایش اطلاعات خرید' : 'ثبت اطلاعات خرید',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
_productDropDown(),
Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Column(
spacing: 12,
children: [_provinceWidget(), _cityWidget()],
),
),
Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Column(
spacing: 12,
children: [
RTextField(
controller: controller.sellerNameController,
label: 'نام فروشنده',
borderColor: AppColor.darkGreyLight,
filled: true,
filledColor: AppColor.bgLight,
),
RTextField(
controller: controller.sellerPhoneController,
label: 'تلفن فروشنده',
keyboardType: TextInputType.phone,
borderColor: AppColor.darkGreyLight,
maxLength: 11,
filled: true,
filledColor: AppColor.bgLight,
validator: (value) {
if (value == null || value.isEmpty) {
return 'لطفاً شماره موبایل را وارد کنید';
}
String cleaned = value.replaceAll(',', '');
if (cleaned.length != 11) {
return 'شماره موبایل باید ۱۱ رقم باشد';
}
if (!cleaned.startsWith('09')) {
return 'شماره موبایل باید با 09 شروع شود';
}
return null;
},
),
UnitTextField(
controller: controller.carcassWeightController,
hint: 'وزن',
unit: 'کیلوگرم',
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
SeparatorInputFormatter(),
],
),
UnitTextField(
controller: controller.carcassCountController,
hint: 'حجم',
unit: 'قطعه',
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
SeparatorInputFormatter(),
],
),
],
),
),
_imageCarcasesWidget(isOnEdit),
submitButtonWidget(isOnEdit),
SizedBox(),
],
),
),
);
}
Widget submitButtonWidget(bool isOnEdit) {
return Obx(() {
return RElevated(
text: isOnEdit ? 'ویرایش' : 'ثبت',
width: Get.width,
backgroundColor: AppColor.greenNormal,
isLoading: controller.isOnLoadingSubmitOrEdit.value,
enabled: controller.isSubmitButtonEnabled.value,
onPressed: isOnEdit
? () async {
await controller.editStewardPurchaseOutOfProvince();
Get.back();
}
: () async {
var res = await controller.createStewardPurchaseOutOfProvince();
if (res) {
Get.back();
}
},
height: 40,
);
});
}
Widget _productDropDown() {
return Obx(() {
return OverlayDropdownWidget<ProductModel>(
items: controller.rootLogic.rolesProductsModel,
height: 56,
hasDropIcon: false,
background: Colors.white,
onChanged: (value) {
controller.selectedProduct.value = value;
},
selectedItem: controller.selectedProduct.value,
initialValue: controller.selectedProduct.value,
itemBuilder: (item) => Text(item.name ?? 'بدون نام'),
labelBuilder: (item) => Row(
spacing: 8,
children: [
(item?.name?.contains('مرغ گرم') ?? false)
? Assets.images.chicken.image(width: 40, height: 40)
: Assets.vec.placeHolderSvg.svg(width: 40, height: 40),
Text(item?.name ?? 'انتخاب محصول'),
Spacer(),
Text(
'موجودی:${controller.rootLogic.inventoryModel.value?.totalRemainWeight.separatedByCommaFa ?? 0}',
),
],
),
);
});
}
Widget _provinceWidget() {
return Obx(() {
return OverlayDropdownWidget<IranProvinceCityModel>(
items: controller.rootLogic.provinces,
onChanged: (value) {
controller.selectedProvince.value = value;
},
selectedItem: controller.selectedProvince.value,
itemBuilder: (item) => Text(
item.name ?? 'بدون نام',
style: AppFonts.yekan14.copyWith(color: AppColor.lightGreyDarker),
),
labelBuilder: (item) => item?.name != null
? Text(
item!.name!,
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
)
: Text(
'انتخاب استان',
style: AppFonts.yekan14.copyWith(
color: AppColor.textColorLight,
),
),
);
});
}
Widget _cityWidget() {
return ObxValue((data) {
return OverlayDropdownWidget<IranProvinceCityModel>(
items: data,
onChanged: (value) {
controller.selectedCity.value = value;
},
selectedItem: controller.selectedCity.value,
itemBuilder: (item) => Text(
item.name ?? 'بدون نام',
style: AppFonts.yekan14.copyWith(color: AppColor.lightGreyDarker),
),
labelBuilder: (item) => item?.name != null
? Text(
item!.name!,
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
)
: Text(
'انتخاب شهر',
style: AppFonts.yekan14.copyWith(
color: AppColor.textColorLight,
),
),
);
}, controller.cites);
}
SizedBox _imageCarcasesWidget(bool isOnEdit) {
return SizedBox(
width: Get.width,
height: 370,
child: Card(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Column(
spacing: 8,
children: [
Text(
'بارنامه',
style: AppFonts.yekan16Bold.copyWith(
color: AppColor.blueNormal,
),
),
Expanded(
child: ObxValue((data) {
return Container(
width: Get.width,
height: 270,
decoration: BoxDecoration(
color: AppColor.lightGreyNormal,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 1, color: AppColor.blackLight),
),
child: Center(
child: isOnEdit
? Image.network(controller.editImageUrl.value ?? '')
: data.value == null
? Padding(
padding: const EdgeInsets.fromLTRB(
30,
10,
10,
30,
),
child: Assets.vec.placeHolderSvg.svg(
width: 200.w,
height: 150.h,
),
)
: Image.file(
File(data.value!.path),
fit: BoxFit.cover,
),
),
);
}, controller.selectedImage),
),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
RElevated(
text: 'گالری',
width: 150.w,
height: 40.h,
textStyle: AppFonts.yekan20.copyWith(color: Colors.white),
onPressed: () async {
controller.selectedImage.value = await controller
.imagePicker
.pickImage(
source: ImageSource.gallery,
imageQuality: 60,
maxWidth: 1080,
maxHeight: 720,
);
},
),
SizedBox(width: 16),
ROutlinedElevated(
text: 'دوربین',
width: 150.w,
height: 40.h,
textStyle: AppFonts.yekan20.copyWith(
color: AppColor.blueNormal,
),
onPressed: () async {
controller.selectedImage.value = await controller
.imagePicker
.pickImage(
source: ImageSource.camera,
imageQuality: 60,
maxWidth: 1080,
maxHeight: 720,
);
},
),
],
),
],
),
),
),
);
}
Widget filterBottomSheet() {
return BaseBottomSheet(
height: 200,
child: Column(
spacing: 16,
children: [
Text(
'فیلترها',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
Row(
spacing: 8,
children: [
Expanded(
child: dateFilterWidget(
date: controller.fromDateFilter,
onChanged: (jalali) =>
controller.fromDateFilter.value = jalali,
),
),
Expanded(
child: dateFilterWidget(
isFrom: false,
date: controller.toDateFilter,
onChanged: (jalali) => controller.toDateFilter.value = jalali,
),
),
],
),
RElevated(
text: 'اعمال فیلتر',
isFullWidth: true,
backgroundColor: AppColor.greenNormal,
onPressed: () {
controller.getStewardPurchaseOutOfProvince();
Get.back();
},
height: 40,
),
],
),
);
}
}

View File

@@ -0,0 +1,97 @@
import 'package:rasadyar_chicken/data/models/response/bar_information/bar_information.dart';
import 'package:rasadyar_chicken/data/models/response/kill_house_distribution_info/kill_house_distribution_info.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/root/logic.dart';
import 'package:rasadyar_core/core.dart';
class WarehouseAndDistributionHomeLogic extends GetxController {
WarehouseAndDistributionRootLogic rootLogic = Get.find<WarehouseAndDistributionRootLogic>();
RxnInt totalWeightTodayBars = RxnInt();
Rxn<KillHouseDistributionInfo> killHouseDistributionInfo = Rxn<KillHouseDistributionInfo>();
Rxn<BarInformation> barInformation = Rxn();
RxList<Map<String, String?>> inventoryItems = [
{'خریدهای دولتی داخل استان': null},
{'خریدهای آزاد داخل استان': null},
{'وزن خریدهای خارج استان': null},
{'کل ورودی به انبار': null},
{'کل فروش': null},
{'مانده انبار': null},
].obs;
RxList<Map<String, String>> broadcastItems = [
{'وزن دولتی': '2،225،256'},
{'وزن آزاد': '2،225،256'},
{'فروش دولتی': '2،225،256'},
{'فروش آزاد': '2،225،256'},
{'توزیع داخل استان': '2،225،256'},
{'توزیع خارج استان': '2،225،256'},
{'قطعه بندی': '2،225،256'},
].obs;
RxBool isExpanded = false.obs;
@override
void onReady() {
super.onReady();
refreshData();
}
Future<void> refreshData() async {
await Future.wait([
getGeneralBarsInformation(),
getTodayBars(),
getDistributionInformation(),
rootLogic.getRolesProducts(),
rootLogic.getKillHouseSalesInfoDashboard(),
]);
}
Future<void> getGeneralBarsInformation() async {
await safeCall<BarInformation?>(
call: () async => await rootLogic.chickenRepository.getGeneralBarInformation(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildQueryParams(role: 'Steward'),
),
onSuccess: (result) {
if (result != null) {
barInformation.value = result;
}
},
onError: (error, stackTrace) {},
);
}
Future<void> getTodayBars() async {
await safeCall<BarInformation?>(
call: () async => await rootLogic.chickenRepository.getGeneralBarInformation(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildQueryParams(
fromDate: DateTime.now(),
toDate: DateTime.now(),
role: 'Steward',
),
),
onSuccess: (result) {
if (result != null) {
totalWeightTodayBars.value = result.totalBarsWeight?.toInt();
}
},
onError: (error, stackTrace) {},
);
}
Future<void> getDistributionInformation() async {
await safeCall<KillHouseDistributionInfo?>(
call: () async => await rootLogic.chickenRepository.getKillHouseDistributionInfo(
token: rootLogic.tokenService.accessToken.value!,
),
onSuccess: (result) {
if (result != null) {
killHouseDistributionInfo.value = result;
}
},
onError: (error, stackTrace) {},
);
}
}

View File

@@ -0,0 +1,276 @@
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:rasadyar_chicken/data/data_source/local/chicken_local.dart';
import 'package:rasadyar_chicken/data/di/chicken_di.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_sales_info_dashboard.dart';
import 'package:rasadyar_chicken/data/models/local/widely_used_local_model.dart';
import 'package:rasadyar_chicken/data/models/response/inventory/inventory_model.dart';
import 'package:rasadyar_chicken/data/models/response/iran_province_city/iran_province_city_model.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/data/models/response/steward_remain_weight/steward_remain_weight.dart';
import 'package:rasadyar_chicken/data/models/response/steward_sales_info_dashboard/steward_sales_info_dashboard.dart';
import 'package:rasadyar_chicken/data/models/response/waiting_arrival/waiting_arrival.dart'
hide ProductModel;
import 'package:rasadyar_chicken/data/repositories/chicken/chicken_repository.dart';
import 'package:rasadyar_chicken/data/repositories/kill_house/kill_house_repository.dart';
import 'package:rasadyar_chicken/presentation/pages/common/profile/view.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/buy/view.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/home/view.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/sale/view.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/segmentation/view.dart';
import 'package:rasadyar_chicken/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/utils/utils.dart';
import 'package:rasadyar_core/core.dart';
enum ErrorLocationType { serviceDisabled, permissionDenied, none }
class WarehouseAndDistributionRootLogic extends GetxController {
DateTime? _lastBackPressed;
RxInt currentPage = 2.obs;
List<Widget> pages = [
WarehouseAndDistributionBuyPage(),
WarehouseAndDistributionSalePage(),
WarehouseAndDistributionHomePage(),
WarehouseAndDistributionSegmentationPage(),
ProfilePage(),
];
final defaultRoutes = <int, String>{
0: ChickenRoutes.buyWarehouseAndDistribution,
1: ChickenRoutes.saleWarehouseAndDistribution,
};
RxList<ProductModel> rolesProductsModel = RxList<ProductModel>();
Rxn<WidelyUsedLocalModel> widelyUsedList = Rxn<WidelyUsedLocalModel>();
Rxn<StewardSalesInfoDashboard> stewardSalesInfoDashboard =
Rxn<StewardSalesInfoDashboard>();
Rxn<StewardRemainWeight> stewardRemainWeight = Rxn<StewardRemainWeight>();
late DioRemote dioRemote;
var tokenService = Get.find<TokenStorageService>();
late ChickenRepository chickenRepository;
late KillHouseRepository killHouseRepository;
late ChickenLocalDataSource localDatasource;
RxList<ErrorLocationType> errorLocationType = RxList();
RxMap<int, dynamic> inventoryExpandedList = RxMap();
Rxn<InventoryModel> inventoryModel = Rxn<InventoryModel>();
Rxn<KillHouseSalesInfoDashboard> killHouseSalesInfoDashboard =
Rxn<KillHouseSalesInfoDashboard>();
RxList<IranProvinceCityModel> provinces = <IranProvinceCityModel>[].obs;
// Cancel tokens for API calls
CancelToken? _inventoryCancelToken;
CancelToken? _provincesCancelToken;
@override
void onInit() {
super.onInit();
localDatasource = diChicken.get<ChickenLocalDataSource>();
chickenRepository = diChicken.get<ChickenRepository>();
killHouseRepository = diChicken.get<KillHouseRepository>();
}
@override
void onReady() {
super.onReady();
if (provinces.isEmpty) {
getProvinces();
}
if (killHouseSalesInfoDashboard.value == null) {
getKillHouseSalesInfoDashboard();
}
if (rolesProductsModel.isEmpty) {
getRolesProducts();
}
getStewardSaleDashboard();
getStewardRemainWeightData();
if (widelyUsedList.value?.hasInit != true) {
//TODO
localDatasource.initWidleyUsed().then(
(value) => localDatasource.getAllWidely(),
);
}
}
@override
void onClose() {
// Cancel any ongoing requests when controller is disposed
_inventoryCancelToken?.cancel();
_provincesCancelToken?.cancel();
super.onClose();
}
Future<void> onRefresh() async {
await Future.wait([
getKillHouseSalesInfoDashboard(),
getRolesProducts(),
getStewardSaleDashboard(),
getStewardRemainWeightData(),
getProvinces(),
getStewardRemainWeightData(),
]);
}
void toggleExpanded(int index) {
if (inventoryExpandedList.keys.contains(index)) {
inventoryExpandedList.remove(index);
} else {
inventoryExpandedList[index] = false;
}
}
Future<void> getKillHouseSalesInfoDashboard() async {
// Cancel previous request if still running
_inventoryCancelToken?.cancel();
_inventoryCancelToken = CancelToken();
await safeCall<KillHouseSalesInfoDashboard?>(
call: () async =>
await killHouseRepository.getKillHouseSalesInfoDashboard(
token: tokenService.accessToken.value!,
cancelToken: _inventoryCancelToken,
),
onSuccess: (result) {
if (result != null) {
killHouseSalesInfoDashboard.value = result;
}
},
onError: (error, stackTrace) {
if (error is DioException && error.type == DioExceptionType.cancel) {
// Request was cancelled, ignore the error
return;
}
},
);
}
void rootErrorHandler(DioException error) {
handleGeneric(error, () {
tokenService.deleteModuleTokens(Module.chicken);
});
}
void changePage(int index) {
currentPage.value = index;
}
Future<void> getProvinces() async {
// Cancel previous request if still running
_provincesCancelToken?.cancel();
_provincesCancelToken = CancelToken();
try {
final res = await chickenRepository.getProvince(
cancelToken: _provincesCancelToken,
);
if (res != null) {
provinces.clear();
provinces.value = res;
}
} catch (e) {
if (e is DioException && e.type == DioExceptionType.cancel) {
// Request was cancelled, ignore the error
return;
}
provinces.clear();
}
}
Future<void> getRolesProducts() async {
safeCall(
call: () async => await chickenRepository.getRolesProducts(
token: tokenService.accessToken.value!,
),
onSuccess: (result) {
if (result != null) {
rolesProductsModel.value = result;
}
},
onError: (error, stacktrace) {},
);
}
Future<void> getStewardSaleDashboard() async {
safeCall(
call: () async => await chickenRepository.getStewardSalesInfoDashboard(
token: tokenService.accessToken.value!,
queryParameters: buildRawQueryParams(role: 'Steward'),
),
onSuccess: (result) {
if (result != null) {
stewardSalesInfoDashboard.value = result;
}
},
onError: (error, stacktrace) {},
);
}
Future<void> getStewardRemainWeightData() async {
safeCall(
call: () async => await chickenRepository.getStewardRemainWeight(
token: tokenService.accessToken.value!,
),
onSuccess: (result) {
if (result != null) {
stewardRemainWeight.value = result;
}
},
onError: (error, stacktrace) {},
);
}
int getNestedKey() {
switch (currentPage.value) {
case 0:
return stewardFirstKey;
case 1:
return stewardSecondKey;
case 2:
return stewardThirdKey;
case 3:
return stewardFourthKey;
case 4:
return stewardFourthKey;
default:
return stewardThirdKey;
}
}
void onPopScopTaped() async {
final nestedKeyId = getNestedKey();
GlobalKey<NavigatorState>? currentNestedKey = Get.nestedKey(nestedKeyId);
if (currentNestedKey?.currentState?.canPop() == true) {
iLog(currentNestedKey?.currentState?.canPop());
iLog(currentNestedKey?.currentContext);
currentNestedKey?.currentState?.popUntil((route) => route.isFirst);
} else {
final now = DateTime.now();
if (_lastBackPressed == null ||
now.difference(_lastBackPressed!) > Duration(seconds: 2)) {
_lastBackPressed = now;
Get.snackbar(
'خروج از برنامه',
'برای خروج دوباره بازگشت را بزنید',
snackPosition: SnackPosition.TOP,
duration: Duration(seconds: 2),
backgroundColor: AppColor.warning,
);
} else {
await SystemNavigator.pop();
}
}
}
bool isKillHouse(WaitingArrivalModel model) =>
model.allocationType?.split("_")[0].toLowerCase() == "killhouse";
}

View File

@@ -0,0 +1,695 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/chicken.dart';
import 'package:rasadyar_chicken/data/models/response/kill_house_distribution_info/kill_house_distribution_info.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/root/logic.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_core/core.dart';
class WarehouseAndDistributionRootPage
extends GetView<WarehouseAndDistributionRootLogic> {
WarehouseAndDistributionRootPage({super.key});
@override
Widget build(BuildContext context) {
return ObxValue((data) {
return ChickenBasePage(
isFullScreen: true,
isBase: true,
onPopScopTaped: controller.onPopScopTaped,
child: Stack(
children: [
IndexedStack(
children: [
Navigator(
key: Get.nestedKey(killHouseWarehouseAndDistributionBuyKey),
onGenerateRoute: (settings) {
final page = ChickenPages.pages.firstWhere(
(e) => e.name == settings.name,
orElse: () => ChickenPages.pages.firstWhere(
(e) =>
e.name == ChickenRoutes.buyWarehouseAndDistribution,
),
);
return buildRouteFromGetPage(page);
},
),
Navigator(
key: Get.nestedKey(killHouseWarehouseAndDistributionSaleKey),
onGenerateRoute: (settings) {
final page = ChickenPages.pages.firstWhere(
(e) => e.name == settings.name,
orElse: () => ChickenPages.pages.firstWhere(
(e) =>
e.name ==
ChickenRoutes.saleWarehouseAndDistribution,
),
);
return buildRouteFromGetPage(page);
},
),
Navigator(
key: Get.nestedKey(stewardThirdKey),
onGenerateRoute: (settings) =>
GetPageRoute(page: () => controller.pages[2]),
),
Navigator(
key: Get.nestedKey(stewardFourthKey),
onGenerateRoute: (settings) =>
GetPageRoute(page: () => controller.pages[3]),
),
Navigator(
key: Get.nestedKey(stewardFifthKey),
onGenerateRoute: (settings) =>
GetPageRoute(page: () => controller.pages[4]),
),
],
index: data.value,
),
Positioned(
bottom: 0,
right: 0,
left: 0,
child: RBottomNavigation(
items: [
RBottomNavigationItem(
label: 'خرید',
icon: Assets.vec.buySvg.path,
isSelected: controller.currentPage.value == 0,
onTap: () {
Get.nestedKey(
stewardFirstKey,
)?.currentState?.popUntil((route) => route.isFirst);
Get.nestedKey(
stewardSecondKey,
)?.currentState?.popUntil((route) => route.isFirst);
controller.changePage(0);
},
),
RBottomNavigationItem(
label: 'فروش',
icon: Assets.vec.saleSvg.path,
isSelected: controller.currentPage.value == 1,
onTap: () {
Get.nestedKey(
stewardFirstKey,
)?.currentState?.popUntil((route) => route.isFirst);
Get.nestedKey(
stewardSecondKey,
)?.currentState?.popUntil((route) => route.isFirst);
controller.changePage(1);
},
),
RBottomNavigationItem(
label: 'خانه',
icon: Assets.vec.homeSvg.path,
isSelected: controller.currentPage.value == 2,
onTap: () {
Get.nestedKey(
stewardSecondKey,
)?.currentState?.popUntil((route) => route.isFirst);
Get.nestedKey(
stewardFirstKey,
)?.currentState?.popUntil((route) => route.isFirst);
controller.changePage(2);
},
),
RBottomNavigationItem(
label: 'قطعه بندی',
icon: Assets.vec.convertCubeSvg.path,
isSelected: controller.currentPage.value == 3,
onTap: () {
Get.nestedKey(
stewardSecondKey,
)?.currentState?.popUntil((route) => route.isFirst);
Get.nestedKey(
stewardFirstKey,
)?.currentState?.popUntil((route) => route.isFirst);
controller.changePage(3);
},
),
RBottomNavigationItem(
label: 'پروفایل',
icon: Assets.vec.profileCircleSvg.path,
isSelected: controller.currentPage.value == 4,
onTap: () {
Get.nestedKey(
stewardSecondKey,
)?.currentState?.popUntil((route) => route.isFirst);
Get.nestedKey(
stewardFirstKey,
)?.currentState?.popUntil((route) => route.isFirst);
controller.changePage(4);
},
),
],
),
),
],
),
);
}, controller.currentPage);
}
Container _todayShipmentWidget() {
return Container(
height: 70,
width: Get.width / 2,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
clipBehavior: Clip.hardEdge,
child: Row(
children: [
Expanded(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [const Color(0xFFEAEFFF), Colors.white],
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 4,
children: [
Assets.icons.cubeScan.svg(width: 30.w, height: 30),
Text(
'بارهای امروز',
textAlign: TextAlign.right,
style: AppFonts.yekan14.copyWith(
color: AppColor.blueNormal,
),
),
],
),
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 4,
children: [
Text(
'2،225،256',
textAlign: TextAlign.right,
style: AppFonts.yekan16.copyWith(color: AppColor.textColor),
),
Text(
'کیلوگرم',
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.textColor),
),
],
),
),
],
),
);
}
Container _informationLabelCard({
required String title,
required String description,
String unit = 'کیلوگرم',
required String iconPath,
required Color iconColor,
required Color bgDescriptionColor,
required Color bgLabelColor,
}) {
return Container(
height: 82,
decoration: BoxDecoration(borderRadius: BorderRadius.circular(8)),
clipBehavior: Clip.hardEdge,
child: Row(
children: [
// Left side with icon and title
Expanded(
child: Container(
height: 82,
decoration: BoxDecoration(
color: bgLabelColor,
borderRadius: BorderRadius.only(
topRight: Radius.circular(8),
bottomRight: Radius.circular(8),
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 4,
children: [
SvgGenImage.vec(iconPath).svg(
width: 24,
height: 24,
colorFilter: ColorFilter.mode(iconColor, BlendMode.srcIn),
),
Text(
title,
textAlign: TextAlign.right,
style: AppFonts.yekan14.copyWith(
color: AppColor.mediumGreyDarkActive,
),
),
],
),
),
),
// Right side with description and unit
Expanded(
child: Container(
decoration: BoxDecoration(
color: bgDescriptionColor,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(8),
bottomLeft: Radius.circular(8),
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 4,
children: [
Text(
description,
textAlign: TextAlign.right,
style: AppFonts.yekan16.copyWith(
color: AppColor.mediumGreyDarkActive,
),
),
Text(
unit,
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(
color: AppColor.mediumGreyDarkActive,
),
),
],
),
),
),
],
),
);
}
Container _informationIconCard({
required String title,
required String description,
String unit = 'کیلوگرم',
required String iconPath,
required Color iconColor,
required Color bgDescriptionColor,
required Color bgLabelColor,
}) {
return Container(
height: 110,
decoration: BoxDecoration(borderRadius: BorderRadius.circular(8)),
clipBehavior: Clip.hardEdge,
child: Stack(
alignment: Alignment.topCenter,
children: [
Positioned(
bottom: 0,
right: 0,
left: 0,
child: Container(
height: 91,
decoration: BoxDecoration(
color: bgDescriptionColor,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 0.25, color: const Color(0xFFB4B4B4)),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 4,
children: [
Text(
title,
textAlign: TextAlign.right,
style: AppFonts.yekan14.copyWith(
color: AppColor.mediumGreyDarkActive,
),
),
Text(
description,
textAlign: TextAlign.right,
style: AppFonts.yekan16.copyWith(
color: AppColor.mediumGreyDarkActive,
),
),
Text(
unit,
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(
color: AppColor.mediumGreyDarkActive,
),
),
],
),
),
),
Positioned(
top: 0,
child: Container(
width: 32,
height: 32,
decoration: ShapeDecoration(
color: bgLabelColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
side: BorderSide(width: 0.25, color: const Color(0xFFD5D5D5)),
),
),
child: Center(
child: SvgGenImage.vec(iconPath).svg(
width: 24,
height: 24,
colorFilter: ColorFilter.mode(iconColor, BlendMode.srcIn),
),
),
),
),
],
),
);
}
Widget widelyUsed({
required String title,
required String iconPath,
required VoidCallback onTap,
}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
spacing: 4,
children: [
Container(
width: 48,
height: 48,
padding: EdgeInsets.all(4),
decoration: ShapeDecoration(
color: const Color(0xFFBECDFF),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: Container(
width: 40,
height: 40,
decoration: ShapeDecoration(
color: AppColor.blueNormal,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: SvgGenImage.vec(iconPath).svg(
width: 24,
height: 24,
colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn),
fit: BoxFit.cover,
),
),
),
Text(
title,
style: AppFonts.yekan10.copyWith(color: AppColor.blueNormal),
),
],
);
}
Widget addWidelyUsed({required VoidCallback onTap}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
spacing: 4,
children: [
Container(
width: 48,
height: 48,
padding: EdgeInsets.all(4),
decoration: ShapeDecoration(
color: const Color(0xFFD9F7F0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: Assets.vec.messageAddSvg.svg(
width: 40,
height: 40,
colorFilter: ColorFilter.mode(
AppColor.greenNormal,
BlendMode.srcIn,
),
fit: BoxFit.cover,
),
),
Text(
'افزودن',
style: AppFonts.yekan10.copyWith(color: AppColor.greenDarkHover),
),
],
);
}
/*Column oldPage() {
return Column(
children: [
inventoryWidget(),
ObxValue((data) => broadcastInformationWidget(data.value), controller.killHouseDistributionInfo),
SizedBox(height: 20),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
cardWidget(
title: 'ورود به انبار',
iconPath: Assets.icons.whareHouse.path,
onTap: () {
Get.toNamed(ChickenRoutes.enteringTheWarehouse);
},
),
cardWidget(
title: 'فروش داخل استان',
iconPath: Assets.icons.inside.path,
onTap: () {
Get.toNamed(ChickenRoutes.salesInProvince);
},
),
cardWidget(
title: 'فروش خارج استان',
iconPath: Assets.icons.outside.path,
onTap: () {
Get.toNamed(ChickenRoutes.salesOutOfProvince);
},
),
],
),
),
],
);
}
Widget inventoryWidget() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
children: [
const SizedBox(height: 20),
Align(
alignment: Alignment.centerRight,
child: Text('موجودی انبار', style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal)),
),
SizedBox(height: 4),
ObxValue(
(data) =>
data.isEmpty
? Container(
margin: const EdgeInsets.symmetric(vertical: 2),
height: 80,
padding: EdgeInsets.all(6),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.blueNormal, width: 1),
),
child: Center(child: CircularProgressIndicator()),
)
: ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: controller.inventoryList.length,
separatorBuilder: (context, index) => const SizedBox(height: 8),
itemBuilder: (context, index) {
return ObxValue((expand) {
return GestureDetector(
onTap: () {
controller.toggleExpanded(index);
},
behavior: HitTestBehavior.opaque,
child: AnimatedContainer(
onEnd: () {
controller.inventoryExpandedList[index] = !controller.inventoryExpandedList[index]!;
},
margin: const EdgeInsets.symmetric(vertical: 2),
padding: EdgeInsets.all(6),
curve: Curves.easeInOut,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.blueNormal, width: 1),
),
duration: const Duration(seconds: 1),
height: expand.keys.contains(index) ? 250 : 80,
child: inventoryItem(
isExpanded: expand.keys.contains(index) && expand[index]!,
index: index,
model: controller.inventoryList[index],
),
),
);
}, controller.inventoryExpandedList);
},
),
controller.inventoryList,
),
],
),
);
}
Widget inventoryItem({required bool isExpanded, required int index, required InventoryModel model}) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 8,
children: [
buildRow('نام محصول', model.name ?? ''),
Visibility(
visible: isExpanded,
child: Column(
spacing: 8,
children: [
buildRow('وزن خریدهای دولتی داخل استان (کیلوگرم)', '0326598653'),
buildRow('وزن خریدهای آزاد داخل استان (کیلوگرم)', model.receiveFreeCarcassesWeight.toString()),
buildRow('وزن خریدهای خارج استان (کیلوگرم)', model.freeBuyingCarcassesWeight.toString()),
buildRow('کل ورودی به انبار (کیلوگرم)', model.totalFreeBarsCarcassesWeight.toString()),
buildRow('کل فروش (کیلوگرم)', model.realAllocatedWeight.toString()),
buildRow('مانده انبار (کیلوگرم)', model.totalRemainWeight.toString()),
],
),
),
],
);
}*/
Widget buildRow(String title, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
flex: 2,
child: Text(
title,
textAlign: TextAlign.right,
style: AppFonts.yekan14.copyWith(
color: AppColor.darkGreyDarkHover,
),
),
),
Flexible(
flex: 1,
child: Text(
value,
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(
color: AppColor.darkGreyDarkHover,
),
),
),
],
),
);
}
Widget broadcastInformationWidget(KillHouseDistributionInfo? model) {
return Container(
height: 140,
margin: const EdgeInsets.all(8),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.blueNormal, width: 1),
),
child: model != null
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 10,
children: [
Text(
'اطلاعات ارسالی',
textAlign: TextAlign.right,
style: AppFonts.yekan16Bold.copyWith(
color: AppColor.blueNormal,
),
),
const SizedBox(height: 12),
buildRow(
'فروش و توزیع داخل استان (کیلوگرم)',
model.stewardAllocationsWeight!.toInt().toString(),
),
buildRow(
'فروش و توزیع خارج استان (کیلوگرم)',
model.freeSalesWeight!.toInt().toString(),
),
],
)
: const Center(child: CircularProgressIndicator()),
);
}
Widget cardWidget({
required String title,
required String iconPath,
required VoidCallback onTap,
}) {
return Container(
width: Get.width / 4,
height: 130,
child: GestureDetector(
onTap: onTap,
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: BorderSide(width: 1, color: AppColor.blueNormal),
),
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SvgGenImage(iconPath).svg(width: 50, height: 50),
SizedBox(height: 4),
Text(
title,
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal),
),
],
),
),
),
),
);
}
}

View File

@@ -0,0 +1,137 @@
import 'package:flutter/services.dart';
import 'package:rasadyar_chicken/data/models/request/conform_allocation/conform_allocation.dart';
import 'package:rasadyar_chicken/data/models/response/allocated_made/allocated_made.dart';
import 'package:rasadyar_chicken/data/models/response/guild/guild_model.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/data/models/response/steward_free_bar_dashboard/steward_free_bar_dashboard.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/root/logic.dart';
import 'package:rasadyar_core/core.dart';
class WarehouseAndDistributionSaleLogic extends GetxController {
Rxn<List<AllocatedMadeModel>?> allocatedMadeModel = Rxn<List<AllocatedMadeModel>?>();
RxList<GuildModel> guildsModel = <GuildModel>[].obs;
Rxn<StewardFreeBarDashboard> stewardFreeDashboard = Rxn<StewardFreeBarDashboard>();
WarehouseAndDistributionRootLogic rootLogic = Get.find<WarehouseAndDistributionRootLogic>();
List<String> routesName = ['فروش'];
DateTime? _lastBackPressed;
@override
void onReady() {
super.onReady();
getStewardDashBord();
}
Future<void> getAllocatedMade() async {
safeCall(
call: () async => await rootLogic.chickenRepository.getAllocatedMade(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildQueryParams(page: 1, pageSize: 20, search: 'filter', role: 'Steward'),
),
onSuccess: (result) {
if (result != null) {
allocatedMadeModel.value = result.results;
}
},
onError: (error, stacktrace) {},
);
}
void checkVerfication() {}
void confirmAllocation(ConformAllocation allocation) {
safeCall(
call: () async => await rootLogic.chickenRepository.confirmAllocation(
token: rootLogic.tokenService.accessToken.value!,
allocation: allocation.toJson(),
),
onSuccess: (result) {
getAllocatedMade();
},
onError: (error, stacktrace) {},
);
}
void denyAllocation(String token) {
safeCall(
call: () async => await rootLogic.chickenRepository.denyAllocation(
token: rootLogic.tokenService.accessToken.value!,
allocationToken: token,
),
onSuccess: (result) {
getAllocatedMade();
},
onError: (error, stacktrace) {},
);
}
Future<void> confirmAllAllocations() async {
safeCall(
call: () async => await rootLogic.chickenRepository.confirmAllAllocation(
token: rootLogic.tokenService.accessToken.value!,
allocationTokens: allocatedMadeModel.value?.map((e) => e.key!).toList() ?? [],
),
onSuccess: (result) {
getAllocatedMade();
},
onError: (error, stacktrace) {},
);
}
Future<void> getGuilds() async {}
Future<void> addSale() async {}
void setSelectedGuild(GuildModel value) {}
void setSelectedProduct(ProductModel value) {}
Future<void> getStewardDashBord() async {
safeCall(
call: () async => await rootLogic.chickenRepository.getStewardDashboard(
token: rootLogic.tokenService.accessToken.value!,
stratDate: DateTime.now().formattedDashedGregorian,
endDate: DateTime.now().formattedDashedGregorian,
),
onSuccess: (result) {
if (result != null) {
stewardFreeDashboard.value = result;
}
},
onError: (error, stacktrace) {},
);
}
Future<void> submitAllocation() async {}
@override
void dispose() {
rootLogic.inventoryExpandedList.clear();
super.dispose();
}
void onPopScopTaped() async {
final now = DateTime.now();
if (_lastBackPressed == null || now.difference(_lastBackPressed!) > Duration(seconds: 2)) {
_lastBackPressed = now;
Get.snackbar(
'خروج از برنامه',
'برای خروج دوباره بازگشت را بزنید',
snackPosition: SnackPosition.TOP,
duration: Duration(seconds: 2),
backgroundColor: AppColor.warning,
);
} else {
await SystemNavigator.pop();
}
}
}

View File

@@ -0,0 +1,183 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/chicken.dart';
import 'package:rasadyar_chicken/data/models/response/steward_free_bar_dashboard/steward_free_bar_dashboard.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class WarehouseAndDistributionSalePage extends GetView<WarehouseAndDistributionSaleLogic> {
WarehouseAndDistributionSalePage({super.key});
@override
Widget build(BuildContext context) {
return ChickenBasePage(
routes: controller.routesName,
isBase: true,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 21,
children: [
GlassMorphismCardIcon(
title: 'فروش داخل استان',
vecIcon: Assets.vec.map2Svg.path,
onTap: () {
Get.toNamed(ChickenRoutes.salesInProvinceSteward, id: stewardSecondKey);
},
),
GlassMorphismCardIcon(
title: 'فروش خارج استان',
vecIcon: Assets.vec.saleOutProvinceSvg.path,
onTap: () {
Get.toNamed(ChickenRoutes.salesOutOfProvinceSteward, id: stewardSecondKey);
},
),
],
),
],
),
);
}
Widget addSaleOutOfTheProvinceBottomSheet() {
return BaseBottomSheet(
child: Column(
children: [
const SizedBox(height: 20),
Align(
alignment: Alignment.centerRight,
child: Text(
'ثبت فروش خارج استان',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
),
SizedBox(height: 4),
RElevated(text: 'ثبت توزیع/ فروش', onPressed: () {}),
],
),
);
}
Widget _typeOuterInfoCard({
required String title,
required String iconPath,
required Color foregroundColor,
VoidCallback? onTap,
}) {
return InkWell(
onTap: onTap,
child: Container(
height: 180,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 1, color: foregroundColor),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
Positioned(
top: -41,
child: SvgGenImage.vec(iconPath).svg(
width: 45,
height: 45,
colorFilter: ColorFilter.mode(foregroundColor, BlendMode.srcIn),
),
),
Assets.vec.shoppingBasketSvg.svg(
width: 55,
height: 60,
colorFilter: ColorFilter.mode(foregroundColor, BlendMode.srcIn),
fit: BoxFit.cover,
),
],
),
const SizedBox(height: 15),
Text(
title,
textAlign: TextAlign.right,
style: AppFonts.yekan16Bold.copyWith(color: foregroundColor),
),
],
),
),
);
}
Widget summaryOfInformation(StewardFreeBarDashboard? model) {
return Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Row(
children: [
Text(
'خلاصه اطلاعات',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
],
),
),
Container(
height: 140,
margin: const EdgeInsets.all(8),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.blueNormal, width: 1),
),
child: model == null
? const Center(child: CircularProgressIndicator())
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 10,
children: [
const SizedBox(height: 12),
buildRow('تعداد کل بارها', model.totalQuantity?.toString() ?? '0'),
buildRow('تعداد کل', model.totalBars?.toString() ?? '0'),
buildRow('وزن کل (کیلوگرم)', model.totalWeight?.toString() ?? '0'),
],
),
),
],
);
}
Widget buildRow(String title, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
flex: 2,
child: Text(
title,
textAlign: TextAlign.right,
style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDarkHover),
),
),
Flexible(
flex: 2,
child: Text(
value,
textAlign: TextAlign.left,
style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDarkHover),
),
),
],
),
);
}
}

View File

@@ -0,0 +1,505 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/request/conform_allocation/conform_allocation.dart';
import 'package:rasadyar_chicken/data/models/request/submit_steward_allocation/submit_steward_allocation.dart';
import 'package:rasadyar_chicken/data/models/response/allocated_made/allocated_made.dart';
import 'package:rasadyar_chicken/data/models/response/broadcast_price/broadcast_price.dart';
import 'package:rasadyar_chicken/data/models/response/guild/guild_model.dart';
import 'package:rasadyar_chicken/data/models/response/guild_profile/guild_profile.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/data/models/response/steward_remain_weight/steward_remain_weight.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/root/logic.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/sale/logic.dart';
import 'package:rasadyar_chicken/presentation/utils/string_utils.dart';
import 'package:rasadyar_chicken/presentation/utils/utils.dart';
import 'package:rasadyar_core/core.dart';
class WarehouseAndDistributionSalesInProvinceLogic extends GetxController {
WarehouseAndDistributionRootLogic rootLogic = Get.find<WarehouseAndDistributionRootLogic>();
WarehouseAndDistributionSaleLogic saleLogic = Get.find<WarehouseAndDistributionSaleLogic>();
RxnString searchedValue = RxnString();
RxInt expandedListIndex = (-1).obs;
RxList<String> routesName = RxList();
Rx<Color> bgConfirmAllColor = AppColor.blueNormal.obs;
final RxBool isLoadingMoreAllocationsMade = false.obs;
Timer? _flashingTimer;
Rx<Resource<PaginationModel<AllocatedMadeModel>>> allocatedList =
Resource<PaginationModel<AllocatedMadeModel>>.loading().obs;
RxList<ProductModel> rolesProductsModel = RxList<ProductModel>();
RxList<GuildModel> guildsModel = <GuildModel>[].obs;
GlobalKey<FormState> formKey = GlobalKey<FormState>();
Rx<Jalali> fromDateFilter = Jalali.now().obs;
Rx<Jalali> toDateFilter = Jalali.now().obs;
Rxn<ProductModel> selectedProductModel = Rxn<ProductModel>();
Rxn<GuildModel> selectedGuildModel = Rxn<GuildModel>();
Rxn<GuildProfile> guildProfile = Rxn<GuildProfile>();
RxInt saleType = 1.obs;
RxInt priceType = 2.obs;
RxInt quotaType = 1.obs;
RxInt weight = 0.obs;
RxInt pricePerKilo = 0.obs;
RxInt totalCost = 0.obs;
RxBool isValid = false.obs;
final weightController = TextEditingController();
final pricePerKiloController = TextEditingController();
final totalCostController = TextEditingController();
final ScrollController scrollControllerAllocationsMade = ScrollController();
final RxInt currentPage = 1.obs;
final RxBool addPageAllocationsMade = false.obs;
final RxBool hasMoreDataAllocationsMade = true.obs;
Rxn<BroadcastPrice> broadcastPrice = Rxn<BroadcastPrice>();
Rxn<AllocatedMadeModel> selectedAllocationModelForUpdate = Rxn<AllocatedMadeModel>();
SubmitStewardAllocation? tmpStewardAllocation;
Rxn<Jalali> productionDate = Rxn(null);
Rxn<int> remainingStock = Rxn(null);
Map<String, DayData> freeProductionDateData = {};
Map<String, DayData> governmentalProductionDateData = {};
@override
void onInit() {
super.onInit();
routesName.value = [...saleLogic.routesName, 'داخل استان'].toList();
getAllocatedMade();
getRolesProducts();
getGuilds();
getGuildProfile();
getBroadcastPrice();
ever(saleType, (callback) {
getGuilds();
});
ever(quotaType, (_) {
remainingStock.value = null;
productionDate.value = null;
});
debounce(weight, time: Duration(milliseconds: 110), (callback) {
totalCost.value = callback * pricePerKilo.value;
});
debounce(pricePerKilo, time: Duration(milliseconds: 100), (callback) {
totalCost.value = callback * weight.value;
});
totalCost.listen((data) {
totalCostController.text = data.toString().separatedByComma;
isValid.value =
weight.value > 0 &&
pricePerKilo.value > 0 &&
totalCost.value > 0 &&
selectedProductModel.value != null &&
selectedGuildModel.value != null;
});
everAll([
totalCost,
weight,
pricePerKilo,
totalCost,
selectedProductModel,
selectedGuildModel,
productionDate,
], (callback) => checkVerification());
scrollControllerAllocationsMade.addListener(() {
if (scrollControllerAllocationsMade.position.pixels >=
scrollControllerAllocationsMade.position.maxScrollExtent - 100) {
addPageAllocationsMade.value = true;
getAllocatedMade();
}
});
debounce(
searchedValue,
(callback) => getAllocatedMade(),
time: Duration(milliseconds: timeDebounce),
);
_updateGovernmentalProductionDateData();
_updateFreeProductionDateData();
ever(rootLogic.stewardRemainWeight, (callback) {
_updateGovernmentalProductionDateData();
_updateFreeProductionDateData();
});
}
void _updateGovernmentalProductionDateData() {
List<RemainWeightDay> dates = rootLogic.stewardRemainWeight.value?.governmental ?? [];
governmentalProductionDateData = {
for (var element in dates)
element.day.toString().toJalali.formatCompactDate(): DayData(
value: element.amount?.toInt(),
),
};
}
void _updateFreeProductionDateData() {
var dates = rootLogic.stewardRemainWeight.value?.free ?? [];
freeProductionDateData = {
for (var element in dates)
element.day.toString().toJalali.formatCompactDate(): DayData(
value: element.amount?.toInt(),
),
};
}
Future<void> getAllocatedMade([bool isLoadingMore = false]) async {
if (isLoadingMore) {
isLoadingMoreAllocationsMade.value = true;
} else {
allocatedList.value = Resource<PaginationModel<AllocatedMadeModel>>.loading();
}
if (searchedValue.value != null &&
searchedValue.value!.trim().isNotEmpty &&
currentPage.value > 1) {
currentPage.value = 1; // Reset to first page if search value is set
}
safeCall(
call: () async => await rootLogic.chickenRepository.getAllocatedMade(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildQueryParams(
page: currentPage.value,
pageSize: 20,
search: 'filter',
role: 'Steward',
value: searchedValue.value,
fromDate: fromDateFilter.value.toDateTime(),
toDate: toDateFilter.value.toDateTime(),
),
),
onSuccess: (res) async {
await Future.delayed(Duration(milliseconds: 200));
if ((res?.count ?? 0) == 0) {
allocatedList.value = Resource<PaginationModel<AllocatedMadeModel>>.empty();
} else {
allocatedList.value = Resource<PaginationModel<AllocatedMadeModel>>.success(
PaginationModel<AllocatedMadeModel>(
count: res?.count ?? 0,
next: res?.next,
previous: res?.previous,
results: isLoadingMore
? [...(allocatedList.value.data?.results ?? []), ...(res?.results ?? [])]
: res?.results ?? [],
),
);
isLoadingMoreAllocationsMade.value = false;
if ((allocatedList.value.data?.results?.length ?? 0) > 1) {
flashingFabBgColor();
}
}
},
onError: (error, stacktrace) {
isLoadingMoreAllocationsMade.value = false;
},
);
}
void checkVerification() {
var hasWeight = quotaType.value == 1
? weight.value <=
(governmentalProductionDateData[productionDate.value?.formatCompactDate()]?.value ??
0)
: weight.value <=
(freeProductionDateData[productionDate.value?.formatCompactDate()]?.value ?? 0);
isValid.value =
weight.value > 0 &&
pricePerKilo.value > 0 &&
totalCost.value > 0 &&
hasWeight &&
selectedProductModel.value != null &&
selectedGuildModel.value != null;
}
void confirmAllocation(ConformAllocation allocation) {
safeCall(
call: () async => await rootLogic.chickenRepository.confirmAllocation(
token: rootLogic.tokenService.accessToken.value!,
allocation: allocation.toJson(),
),
onSuccess: (result) {
getAllocatedMade();
},
onError: (error, stacktrace) {},
);
}
void denyAllocation(String token) {
safeCall(
call: () async => await rootLogic.chickenRepository.denyAllocation(
token: rootLogic.tokenService.accessToken.value!,
allocationToken: token,
),
onSuccess: (result) {
getAllocatedMade();
},
onError: (error, stacktrace) {},
);
}
Future<void> confirmAllAllocations() async {
safeCall(
call: () async => await rootLogic.chickenRepository.confirmAllAllocation(
token: rootLogic.tokenService.accessToken.value!,
allocationTokens: allocatedList.value.data?.results?.map((e) => e.key!).toList() ?? [],
),
onSuccess: (result) {
getAllocatedMade();
},
onError: (error, stacktrace) {},
);
}
Future<void> getRolesProducts() async {
safeCall(
call: () async => await rootLogic.chickenRepository.getRolesProducts(
token: rootLogic.tokenService.accessToken.value!,
),
onSuccess: (result) {
if (result != null) {
rolesProductsModel.value = result;
selectedProductModel.value = result.first;
}
},
onError: (error, stacktrace) {},
);
}
Future<void> getGuilds() async {
safeCall(
call: () async => await rootLogic.chickenRepository.getGuilds(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildQueryParams(
//queryParams: {'free': saleType.value == 2 ? true : false},
queryParams: {'all': true},
role: 'Steward',
),
),
onSuccess: (result) {
if (result != null) {
guildsModel.clear();
guildsModel.addAll(result);
}
},
onError: (error, stacktrace) {},
);
}
Future<void> addSale() async {}
void setSelectedGuild(GuildModel value) {
selectedGuildModel.value = value;
update();
}
void setSelectedProduct(ProductModel value) {
selectedProductModel.value = value;
update();
}
Future<void> getGuildProfile() async {
await safeCall(
call: () async => await rootLogic.chickenRepository.getProfile(
token: rootLogic.tokenService.accessToken.value!,
),
onError: (error, stackTrace) {},
onSuccess: (result) {
guildProfile.value = result;
},
);
}
void setSubmitData() {
tmpStewardAllocation = SubmitStewardAllocation(
approvedPriceStatus: priceType.value == 1,
allocationType:
'${guildProfile.value?.steward == true ? "steward" : "guild"}_${selectedGuildModel.value?.steward == true ? "steward" : "guild"}',
sellerType: guildProfile.value?.steward == true ? "Steward" : "Guild",
buyerType: selectedGuildModel.value?.steward == true ? "Steward" : "Guild",
amount: pricePerKilo.value,
totalAmount: totalCost.value,
weightOfCarcasses: weight.value,
sellType: saleType.value == 2 ? "free" : 'exclusive',
numberOfCarcasses: 0,
productionDate: productionDate.value?.toDateTime().formattedDashedGregorian,
quota: quotaType.value == 1 ? 'governmental' : 'free',
guildKey: selectedGuildModel.value?.key,
productKey: selectedProductModel.value?.key,
date: DateTime.now().formattedDashedGregorian,
type: "manual",
);
}
Future<void> submitAllocation() async {
setSubmitData();
safeCall(
showError: true,
call: () async => await rootLogic.chickenRepository.postSubmitStewardAllocation(
token: rootLogic.tokenService.accessToken.value!,
request: tmpStewardAllocation!,
),
onSuccess: (result) {
clearForm();
onRefresh();
rootLogic.onRefresh();
Future.delayed(Duration(seconds: 1), () => defaultShowSuccessMessage("ثبت موفق بود"));
Get.back();
},
onError: (error, stackTrace) {},
);
}
Future<void> deleteAllocation(AllocatedMadeModel model) async {
safeCall(
call: () async => await rootLogic.chickenRepository.deleteStewardAllocation(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: {'steward_allocation_key': model.key},
),
onSuccess: (result) {
getAllocatedMade();
},
onError: (error, stackTrace) {},
);
}
@override
void dispose() {
rootLogic.inventoryExpandedList.clear();
stopFlashing();
super.dispose();
}
void setEditData(AllocatedMadeModel item) {
selectedAllocationModelForUpdate.value = item;
selectedProductModel.value = rolesProductsModel.first;
selectedGuildModel.value = GuildModel(guildsName: 'tst');
weight.value = item.weightOfCarcasses ?? 0;
pricePerKilo.value = item.amount ?? 0;
totalCost.value = item.totalAmount ?? 0;
weightController.text = weight.value.toString().separatedByComma;
pricePerKiloController.text = pricePerKilo.value.toString().separatedByComma;
totalCostController.text = totalCost.value.toString().separatedByComma;
isValid.value = true;
productionDate.value = item.productionDate.toJalali;
}
void clearForm() {
selectedGuildModel.value = null;
weight.value = 0;
totalCost.value = 0;
weightController.clear();
if (broadcastPrice.value?.active == false) {
pricePerKilo.value = 0;
pricePerKiloController.clear();
}
totalCostController.clear();
isValid.value = false;
productionDate.value = null;
quotaType.value = 1;
priceType.value = 2;
saleType.value = 2;
}
Future<void> updateAllocation() async {
ConformAllocation updatedAllocationModel = ConformAllocation(
allocation_key: selectedAllocationModelForUpdate.value?.key,
amount: pricePerKilo.value,
total_amount: totalCost.value,
number_of_carcasses: 0,
weight_of_carcasses: weight.value,
);
safeCall(
showError: true,
call: () async => await rootLogic.chickenRepository.updateStewardAllocation(
token: rootLogic.tokenService.accessToken.value!,
request: updatedAllocationModel,
),
onSuccess: (result) {
clearForm();
onRefresh();
rootLogic.onRefresh();
Future.delayed(Duration(seconds: 1), () => defaultShowSuccessMessage("ویرایش موفق بود"));
Get.back();
},
onError: (error, stackTrace) {},
);
}
void setSearchValue(String? data) {
searchedValue.value = data?.trim();
}
void flashingFabBgColor() {
_flashingTimer?.cancel();
_flashingTimer = Timer.periodic(Duration(seconds: 2), (timer) {
if (bgConfirmAllColor.value == AppColor.blueNormal) {
bgConfirmAllColor.value = AppColor.blueLightHover;
} else {
bgConfirmAllColor.value = AppColor.blueNormal;
}
});
}
void stopFlashing() {
_flashingTimer?.cancel();
_flashingTimer = null;
bgConfirmAllColor.value = AppColor.blueNormal; // بازگرداندن به رنگ پیش‌فرض
}
Steward? getBuyerInformation(AllocatedMadeModel model) {
if (model.allocationType?.buyerIsGuild ?? false) {
return model.toGuilds;
} else {
return model.steward;
}
}
Future<void> getBroadcastPrice() async {
safeCall(
call: () async => await rootLogic.chickenRepository.getBroadcastPrice(
token: rootLogic.tokenService.accessToken.value!,
),
onSuccess: (result) {
broadcastPrice.value = result;
if (broadcastPrice.value?.active == true) {
pricePerKilo.value = broadcastPrice.value?.stewardPrice ?? 0;
pricePerKiloController.text = pricePerKilo.value.toString().separatedByComma;
priceType.value = 2;
}
},
onError: (error, stacktrace) {},
);
}
Future<void> onRefresh() async {
toggleExpansion();
currentPage.value = 1;
hasMoreDataAllocationsMade.value = true;
await Future.wait([getAllocatedMade(), getRolesProducts(), rootLogic.onRefresh()]);
}
void toggleExpansion({int? index}) {
if (expandedListIndex.value == index || index == null) {
expandedListIndex.value = -1;
} else {
expandedListIndex.value = index;
}
}
}

View File

@@ -0,0 +1,543 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/response/allocated_made/allocated_made.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/sales_in_province/widgets/cu_sale_in_provience.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/utils/string_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_chicken/presentation/widget/inventory/inventory_widget.dart';
import 'package:rasadyar_core/core.dart' hide modalDatePicker;
import 'logic.dart';
class WarehouseAndDistributionSalesInProvincePage
extends GetView<WarehouseAndDistributionSalesInProvinceLogic> {
const WarehouseAndDistributionSalesInProvincePage({super.key});
@override
Widget build(BuildContext context) {
return ChickenBasePage(
routes: controller.routesName,
backId: stewardSecondKey,
onSearchChanged: (data) => controller.setSearchValue(data),
onRefresh: controller.onRefresh,
onFilterTap: () {
Get.bottomSheet(filterBottomSheet());
},
child: Stack(
children: [
Positioned.fill(
child: Column(
children: [
// inventoryWidget(controller.rootLogic),
Expanded(
child: ObxValue((data) {
return RPaginatedListView(
listType: ListType.separated,
resource: data.value,
hasMore: data.value.data?.next != null,
isPaginating:
controller.isLoadingMoreAllocationsMade.value,
onLoadMore: () async {
controller.currentPage.value++;
await controller.getAllocatedMade(true);
},
padding: EdgeInsets.fromLTRB(8, 8, 8, 80),
itemBuilder: (context, index) {
var item = data.value.data!.results![index];
return ObxValue((val) {
return ExpandableListItem2(
selected: val.value == index,
onTap: () =>
controller.toggleExpansion(index: index),
index: index,
child: itemListWidget(item),
secondChild: itemListExpandedWidget(item, index),
labelColor: AppColor.blueLight,
labelIcon: Assets.vec.timerSvg.path,
labelIconColor: item.registrationCode == null
? AppColor.darkGreyDark
: AppColor.error,
);
}, controller.expandedListIndex);
},
itemCount: data.value.data?.results?.length ?? 0,
separatorBuilder: (context, index) =>
SizedBox(height: 8.h),
);
}, controller.allocatedList),
),
],
),
),
Positioned(
right: 5,
bottom: 95,
child: SizedBox(
width: Get.width - 30,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
RFab.add(
onPressed: () {
/* Get.bottomSheet(
addOrEditBottomSheet(controller),
isScrollControlled: true,
backgroundColor: Colors.transparent,
).whenComplete(() {
controller.clearForm();
}); */
},
),
ObxValue((data) {
return Visibility(
visible: (data.value.data?.results?.length ?? 0) > 1,
child: AnimatedFab(
onPressed: () async {
Get.defaultDialog(
title: 'تایید یکجا',
middleText:
'آیا از تایید تمامی تخصیص ها اطمینان دارید؟',
confirm: ElevatedButton(
onPressed: () async {
await controller.confirmAllAllocations();
controller.getAllocatedMade();
controller.rootLogic.getKillHouseSalesInfoDashboard();
Get.back();
},
child: Text('تایید'),
style: ElevatedButton.styleFrom(
backgroundColor: AppColor.blueNormal,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
cancel: OutlinedButton(
style: OutlinedButton.styleFrom(
foregroundColor: AppColor.error,
enableFeedback: true,
side: BorderSide(
color: AppColor.error,
width: 1,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
onPressed: () {
Get.back();
},
child: Text('لغو'),
),
);
},
message: 'تایید یکجا',
icon: Assets.vec.clipboardTaskSvg.svg(
width: 40.w,
height: 40.h,
),
backgroundColor: controller.bgConfirmAllColor.value,
),
);
}, controller.allocatedList),
],
),
),
),
],
),
);
}
Row itemListWidget(AllocatedMadeModel item) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(width: 20),
Expanded(
flex: 2,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 4,
children: [
Text(
controller.getBuyerInformation(item)?.user?.fullname ?? 'ندارد',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
SizedBox(height: 2),
Text(
item.createDate?.formattedJalaliDate ?? 'ندارد',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark),
),
],
),
),
Expanded(
flex: 3,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
spacing: 6,
children: [
Visibility(
visible: item.product?.name?.contains('مرغ گرم') ?? false,
child: Assets.vec.hotChickenSvg.svg(
width: 24,
height: 24,
colorFilter: ColorFilter.mode(
AppColor.blueNormal,
BlendMode.srcIn,
),
),
),
Text(
item.weightOfCarcasses!.separatedByCommaFa.addKg,
textAlign: TextAlign.left,
textDirection: TextDirection.ltr,
style: AppFonts.yekan12Bold.copyWith(
color: AppColor.blueNormal,
),
),
],
),
SizedBox(height: 2),
Text(
item.amount.separatedByCommaFa.addReal,
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.darkGreyDark),
),
],
),
),
SizedBox(width: 8),
Expanded(
flex: 2,
child: Column(
spacing: 3,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
item.approvedPriceStatus == true
? 'دولتی'
: item.approvedPriceStatus == false
? 'آزاد'
: '-',
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(
color: item.approvedPriceStatus == true
? AppColor.blueNormal
: AppColor.greenNormal,
),
),
],
),
),
SizedBox(width: 8),
],
);
}
Container itemListExpandedWidget(AllocatedMadeModel item, int index) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Column(
spacing: 8,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
controller.getBuyerInformation(item)?.user?.fullname ?? 'ندارد',
textAlign: TextAlign.center,
style: AppFonts.yekan16.copyWith(color: AppColor.greenDark),
),
Spacer(),
Text(
item.registrationCode == null
? 'در انتظار'
: 'در انتظار تایید خریدار',
textAlign: TextAlign.center,
style: AppFonts.yekan10.copyWith(
color: item.registrationCode == null
? AppColor.darkGreyDark
: AppColor.error,
),
),
SizedBox(width: 7),
Assets.vec.clockSvg.svg(
width: 16.w,
height: 16.h,
colorFilter: ColorFilter.mode(
item.registrationCode == null
? AppColor.darkGreyDark
: AppColor.error,
BlendMode.srcIn,
),
),
],
),
Container(
height: 32,
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: ShapeDecoration(
color: AppColor.blueLight,
shape: RoundedRectangleBorder(
side: BorderSide(width: 1, color: AppColor.blueLightHover),
borderRadius: BorderRadius.circular(8),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
spacing: 3,
children: [
Text(
item.date?.toJalali.formatter.wN ?? 'ندارد',
style: AppFonts.yekan14.copyWith(
color: AppColor.textColor,
),
),
Text(
'${item.date?.toJalali.formatter.d} ${item.date?.toJalali.formatter.mN ?? 'ندارد'}',
style: AppFonts.yekan14.copyWith(
color: AppColor.blueNormal,
),
),
],
),
Text(
'${item.date?.toJalali.formatter.y}',
style: AppFonts.yekan20.copyWith(color: AppColor.textColor),
),
Text(
'${item.date?.toJalali.formatter.tHH}:${item.date?.toJalali.formatter.tMM ?? 'ندارد'}',
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
),
],
),
),
buildRow(
title: 'تلفن خریدار',
value:
controller.getBuyerInformation(item)?.user?.mobile ?? 'ندارد',
valueStyle: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
buildRow(title: 'محصول', value: item.product?.name ?? 'ندارد'),
buildRow(
title: 'تاریخ تولید گوشت',
value: item.productionDate?.toJalali.formatCompactDate() ?? 'ندارد',
),
buildRow(
title: 'نوع تخصیص',
value: item.allocationType?.faAllocationType ?? 'ندارد',
),
buildRow(
title: 'نوع فروش',
value: (item.approvedPriceStatus ?? false) ? 'دولتی' : 'آزاد',
),
buildRow(
title: 'نوع انبار',
value: (item.quota == 'governmental') ? 'دولتی' : 'آزاد',
),
buildRow(
title: 'وزن خریداری شده',
value: '${item.weightOfCarcasses?.separatedByCommaFa} کیلوگرم',
),
buildRow(
title: 'افت وزن(کیلوگرم)',
value: item.weightLossOfCarcasses?.toInt().toString() ?? 'ندارد',
),
buildRow(
title: 'قیمت هر کیلوگرم',
titleLabel: (item.approvedPriceStatus ?? false) ? 'دولتی' : 'آزاد',
titleLabelStyle: AppFonts.yekan14Bold.copyWith(
color: (item.approvedPriceStatus ?? false)
? AppColor.blueNormal
: AppColor.greenNormal,
),
value: '${item.amount?.separatedByCommaFa} ریال',
),
buildRow(
title: 'قیمت کل',
value: '${item.totalAmount?.separatedByCommaFa} ریال',
),
buildRow(
title: 'کداحراز',
value: item.registrationCode?.toString() ?? 'ندارد',
),
buildRow(
title: 'وضعیت کد احراز',
value: item.systemRegistrationCode == true
? "ارسال شده"
: "ارسال نشده",
),
Visibility(
visible: item.registrationCode == null,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 16.w,
children: [
RElevated(
text: 'ویرایش',
width: 150.w,
height: 40.h,
onPressed: () {
controller.setEditData(item);
/* Get.bottomSheet(
addOrEditBottomSheet(controller, isEditMode: true),
isScrollControlled: true,
backgroundColor: Colors.transparent,
).whenComplete(() {
controller.clearForm();
}); */
},
textStyle: AppFonts.yekan20.copyWith(color: Colors.white),
backgroundColor: AppColor.greenNormal,
),
ROutlinedElevated(
text: 'حذف',
textStyle: AppFonts.yekan20.copyWith(
color: AppColor.redNormal,
),
width: 150.w,
height: 40.h,
onPressed: () {
buildDeleteDialog(
onConfirm: () async {
controller.toggleExpansion(index: index);
await controller.deleteAllocation(item);
},
onRefresh: controller.onRefresh,
);
},
borderColor: AppColor.redNormal,
),
],
),
),
],
),
);
}
Widget filterBottomSheet() {
return BaseBottomSheet(
height: 200,
child: Column(
spacing: 16,
children: [
Text(
'فیلترها',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
Row(
spacing: 8,
children: [
Expanded(
child: timeFilterWidget(
controller: controller,
date: controller.fromDateFilter,
onChanged: (jalali) =>
controller.fromDateFilter.value = jalali,
),
),
Expanded(
child: timeFilterWidget(
controller: controller,
isFrom: false,
date: controller.toDateFilter,
onChanged: (jalali) => controller.toDateFilter.value = jalali,
),
),
],
),
RElevated(
text: 'اعمال فیلتر',
isFullWidth: true,
backgroundColor: AppColor.greenNormal,
onPressed: () {
controller.getAllocatedMade();
Get.back();
},
height: 40,
),
],
),
);
}
GestureDetector timeFilterWidget({
required WarehouseAndDistributionSalesInProvinceLogic controller,
isFrom = true,
required Rx<Jalali> date,
required Function(Jalali jalali) onChanged,
}) {
return GestureDetector(
onTap: () {
Get.bottomSheet(modalDatePicker((value) => onChanged(value)));
},
child: Container(
height: 35,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 1, color: AppColor.blueNormal),
),
padding: EdgeInsets.symmetric(horizontal: 11, vertical: 4),
child: Row(
spacing: 8,
children: [
Assets.vec.calendarSvg.svg(
width: 24,
height: 24,
colorFilter: const ColorFilter.mode(
AppColor.blueNormal,
BlendMode.srcIn,
),
),
Text(
isFrom ? 'از' : 'تا',
style: AppFonts.yekan16.copyWith(color: AppColor.blueNormal),
),
Expanded(
child: ObxValue((data) {
return Text(
date.value.formatCompactDate(),
textAlign: TextAlign.center,
style: AppFonts.yekan16.copyWith(
color: AppColor.lightGreyNormalActive,
),
);
}, date),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,515 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/sales_in_province/logic.dart';
import 'package:rasadyar_core/core.dart';
Widget addOrEditBottomSheet(WarehouseAndDistributionSalesInProvinceLogic controller, {bool isEditMode = false}) {
return BaseBottomSheet(
height: Get.height * (isEditMode ? 0.60 : 0.75),
child: Form(
key: controller.formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'${isEditMode ? 'ویرایش' : 'ثبت'} توزیع/ فروش',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
const SizedBox(height: 12),
productDropDown(controller),
const SizedBox(height: 12),
Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Column(
spacing: 12,
children: [
const SizedBox(height: 8),
ObxValue((data) {
return RTextField(
controller: TextEditingController(),
filledColor: AppColor.bgLight,
filled: true,
label: 'تاریخ',
onTap: () {
Get.bottomSheet(
modalDatePicker((value) {
controller.fromDateFilter.value = value;
controller.fromDateFilter.refresh();
}),
);
},
borderColor: AppColor.darkGreyLight,
initText: (data.value).formatCompactDate(),
);
}, controller.fromDateFilter),
Visibility(
visible: isEditMode == false,
child: Container(
height: 50.h,
clipBehavior: Clip.none,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Stack(
fit: StackFit.expand,
alignment: Alignment.center,
clipBehavior: Clip.none,
children: [
Positioned(
child: Container(color: Colors.white, child: Text("انبار")),
top: -10,
right: 8,
),
Obx(() {
return RadioGroup(
groupValue: controller.quotaType.value,
onChanged: (value) {
controller.quotaType.value = value ?? 0;
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: GestureDetector(
onTap: () {
controller.quotaType.value = 1;
},
child: Row(
children: [
Radio(value: 1),
Text('دولتی', style: AppFonts.yekan14),
],
),
),
),
Expanded(
child: GestureDetector(
onTap: () {
controller.quotaType.value = 2;
},
child: Row(
children: [
Radio(value: 2),
Text('آزاد', style: AppFonts.yekan14),
],
),
),
),
],
),
);
}),
],
),
),
),
Obx(() {
return MonthlyDataCalendar(
label: 'تاریخ تولید گوشت',
selectedDate: controller.productionDate.value?.formatCompactDate(),
onDateSelect: (value) {
controller.productionDate.value = value.date;
controller.remainingStock.value = value.remainingStock;
},
dayData: controller.quotaType.value == 1
? controller.governmentalProductionDateData
: controller.freeProductionDateData,
);
}),
Visibility(visible: isEditMode == false, child: guildsDropDown(controller)),
RTextField(
controller: controller.weightController,
keyboardType: TextInputType.number,
autoValidateMode: AutovalidateMode.onUserInteraction,
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
SeparatorInputFormatter(),
],
validator: (value) {
if ((int.tryParse(value?.clearComma ?? '0') ?? 0) >
(controller.remainingStock.value ?? 0)) {
return 'وزن تخصیصی بیشتر از موجودی انبار است';
}
return null;
},
onChanged: (p0) {
controller.weight.value = int.tryParse(p0.clearComma) ?? 0;
},
label: 'وزن لاشه (کیلوگرم)',
),
Visibility(
visible: isEditMode == false,
child: Container(
height: 58.h,
clipBehavior: Clip.none,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Stack(
fit: StackFit.expand,
alignment: Alignment.center,
clipBehavior: Clip.none,
children: [
Positioned(
child: Container(color: Colors.white, child: Text("فروش")),
top: -10,
right: 8,
),
Obx(() {
return RadioGroup(
groupValue: controller.priceType.value,
onChanged: (value) {
controller.priceType.value = value!;
},
child: Row(
children: [
Expanded(
child: GestureDetector(
onTap: (controller.broadcastPrice.value?.active ?? false)
? () {
controller.priceType.value = 1;
}
: null,
child: Row(
children: [
Radio(
value: 1,
enabled: controller.broadcastPrice.value?.active ?? false,
),
Text(
'قیمت مصوب',
style: AppFonts.yekan14.copyWith(
color:
(controller.broadcastPrice.value?.active ?? false)
? AppColor.textColor
: AppColor.labelTextColor,
),
),
],
),
),
),
Expanded(
child: GestureDetector(
onTap: () {
controller.priceType.value = 2;
},
child: Row(
children: [
Radio(value: 2),
Text('قیمت آزاد', style: AppFonts.yekan14),
],
),
),
),
],
),
);
}),
],
),
),
),
ObxValue((data) {
return RTextField(
variant: RTextFieldVariant.noBorder,
controller: controller.pricePerKiloController,
borderColor: AppColor.darkGreyLight,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
SeparatorInputFormatter(),
],
filledColor: AppColor.bgLight,
filled: true,
readonly: data.value == 1,
onChanged: (p0) {
controller.pricePerKilo.value = int.tryParse(p0.clearComma) ?? 0;
},
keyboardType: TextInputType.number,
label: 'قیمت هر کیلو (ريال)',
);
}, controller.priceType),
RTextField(
variant: RTextFieldVariant.noBorder,
enabled: false,
keyboardType: TextInputType.number,
filledColor: AppColor.bgLight,
filled: true,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
SeparatorInputFormatter(),
],
controller: controller.totalCostController,
label: 'هزینه کل (ريال)',
),
],
),
),
SizedBox(height: 12.h),
ObxValue((data) {
return RElevated(
text: isEditMode ? 'ویرایش' : 'ثبت',
isFullWidth: true,
textStyle: AppFonts.yekan16.copyWith(color: Colors.white),
backgroundColor: AppColor.greenNormal,
height: 40,
enabled: data.value,
onPressed: isEditMode
? () async {
await controller.updateAllocation();
Get.back();
}
: () async {
await controller.submitAllocation();
Get.back();
},
);
}, controller.isValid),
const SizedBox(height: 20),
],
),
),
);
}
Widget guildsDropDown(WarehouseAndDistributionSalesInProvinceLogic controller) {
return Obx(() {
final item = controller.selectedGuildModel.value;
return SearchableDropdown(
onChanged: (value) {
controller.selectedGuildModel.value = value;
},
selectedItem: [?item],
singleSelect: false,
items: controller.guildsModel,
hintText: 'انتخاب مباشر/صنف',
itemBuilder: (item) => Text(
item.user != null
? '${item.steward == true ? 'مباشر' : 'صنف'} ${item.user!.fullname} (${item.user!.mobile})'
: 'بدون نام',
),
multiLabelBuilder: (item) => Container(
decoration: BoxDecoration(
color: AppColor.bgLight,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight),
),
padding: EdgeInsets.all(4),
child: Row(
children: [
Text(
item?.user != null
? '${item?.steward == true ? 'مباشر' : 'صنف'} ${item?.user!.fullname}'
: 'بدون نام',
style: AppFonts.yekan14,
),
SizedBox(width: 4.w),
Icon(Icons.close, size: 16, color: AppColor.labelTextColor),
],
),
),
onSearch: (query) async {
return Future.microtask(() {
return RxList(
controller.guildsModel
.where((element) => element.user?.fullname?.contains(query) ?? false)
.toList(),
);
});
},
);
});
}
Widget productDropDown(WarehouseAndDistributionSalesInProvinceLogic controller) {
return Obx(() {
return OverlayDropdownWidget<ProductModel>(
items: controller.rolesProductsModel,
height: 56,
hasDropIcon: false,
background: Colors.white,
onChanged: (value) {
controller.selectedProductModel.value = value;
},
selectedItem: controller.selectedProductModel.value,
itemBuilder: (item) => Text(item.name ?? 'بدون نام'),
labelBuilder: (item) => Row(
spacing: 8,
children: [
(item?.name?.contains('مرغ گرم') ?? false)
? Assets.images.chicken.image(width: 40, height: 40)
: Assets.vec.placeHolderSvg.svg(width: 40, height: 40),
Text(item?.name ?? 'انتخاب محصول'),
Spacer(),
ObxValue((data) {
return Visibility(visible: data.value != null, child: Text('موجودی: $data'));
}, controller.remainingStock),
],
),
);
});
}
Container modalDatePicker(ValueChanged<Jalali> onDateSelected) {
Jalali? tempPickedDate;
return Container(
height: 250,
color: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
child: Row(
children: [
SizedBox(width: 20),
RElevated(
height: 35,
width: 70,
textStyle: AppFonts.yekan14.copyWith(color: Colors.white),
onPressed: () {
onDateSelected(tempPickedDate ?? Jalali.now());
Get.back();
},
text: 'تایید',
),
Spacer(),
RElevated(
height: 35,
width: 70,
backgroundColor: AppColor.error,
textStyle: AppFonts.yekan14.copyWith(color: Colors.white),
onPressed: () {
onDateSelected(tempPickedDate ?? Jalali.now());
Get.back();
},
text: 'لغو',
),
SizedBox(width: 20),
],
),
),
Divider(height: 0, thickness: 1),
Expanded(
child: Container(
child: PersianCupertinoDatePicker(
initialDateTime: Jalali.now(),
minimumDate: Jalali.now().add(days: -1),
maximumDate: Jalali.now(),
mode: PersianCupertinoDatePickerMode.date,
onDateTimeChanged: (dateTime) {
tempPickedDate = dateTime;
},
),
),
),
],
),
);
}
Widget show2StepAddBottomSheet(WarehouseAndDistributionSalesInProvinceLogic controller) {
return BaseBottomSheet(
height: Get.height * .39,
child: Column(
spacing: 8,
children: [
buildRow(
title: 'تاریخ ثبت',
value: controller.tmpStewardAllocation?.date?.formattedJalaliDate ?? 'ندارد',
),
buildRow(
title: 'نام و نام خانوادگی خریدار',
value:
controller.guildsModel
.firstWhere((p0) => p0.key == controller.tmpStewardAllocation?.guildKey)
.user
?.fullname ??
'ندارد',
),
buildRow(
title: 'شماره خریدار',
value:
controller.guildsModel
.firstWhere((p0) => p0.key == controller.tmpStewardAllocation?.guildKey)
.user
?.mobile ??
'ندارد',
),
buildRow(
title: 'قیمت هر کیلو',
value: '${controller.tmpStewardAllocation?.amount.separatedByCommaFa ?? 0} ریال ',
),
buildRow(
title: 'وزن تخصیصی',
value:
'${controller.tmpStewardAllocation?.weightOfCarcasses?.toInt().separatedByCommaFa ?? 0} کیلوگرم',
),
buildRow(
title: 'قیمت کل',
value: '${controller.tmpStewardAllocation?.totalAmount.separatedByCommaFa ?? 0} ریال',
),
Row(
spacing: 10,
children: [
Expanded(
child: RElevated(
backgroundColor: AppColor.greenNormal,
height: 40,
text: 'ثبت',
textStyle: AppFonts.yekan18.copyWith(color: Colors.white),
onPressed: () async {
await controller.submitAllocation();
Get
..back()
..back();
},
),
),
Expanded(
child: ROutlinedElevated(
height: 40,
borderColor: AppColor.error,
text: ' بازگشت',
textStyle: AppFonts.yekan18.copyWith(color: AppColor.error),
onPressed: () {
Get
..back()
..back();
},
),
),
],
),
],
),
);
}

View File

@@ -0,0 +1,382 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/request/steward_free_sale_bar/steward_free_sale_bar_request.dart';
import 'package:rasadyar_chicken/data/models/response/broadcast_price/broadcast_price.dart';
import 'package:rasadyar_chicken/data/models/response/iran_province_city/iran_province_city_model.dart';
import 'package:rasadyar_chicken/data/models/response/out_province_carcasses_buyer/out_province_carcasses_buyer.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/data/models/response/steward_free_sale_bar/steward_free_sale_bar.dart';
import 'package:rasadyar_chicken/data/models/response/steward_remain_weight/steward_remain_weight.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/root/logic.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/sale/logic.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/sales_out_of_province_buyers/logic.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/sales_out_of_province_sales_list/logic.dart';
import 'package:rasadyar_chicken/presentation/utils/utils.dart';
import 'package:rasadyar_core/core.dart';
class WarehouseAndDistributionSalesOutOfProvinceLogic extends GetxController {
WarehouseAndDistributionRootLogic rootLogic = Get.find<WarehouseAndDistributionRootLogic>();
WarehouseAndDistributionSaleLogic saleLogic = Get.find<WarehouseAndDistributionSaleLogic>();
WarehouseAndDistributionSalesOutOfProvinceSalesListLogic saleListLogic = Get.find<WarehouseAndDistributionSalesOutOfProvinceSalesListLogic>();
WarehouseAndDistributionSalesOutOfProvinceBuyersLogic buyerLogic = Get.find<WarehouseAndDistributionSalesOutOfProvinceBuyersLogic>();
RxBool isExpanded = false.obs;
RxInt currentPage = 1.obs;
RxBool isSaleSubmitButtonEnabled = false.obs;
RxInt expandedListIndex = (-1).obs;
Rx<Jalali> fromDateFilter = Jalali.now().obs;
Rx<Jalali> toDateFilter = Jalali.now().obs;
RxnString searchedValue = RxnString();
RxList<String> routesName = RxList();
RxBool isLoadingMoreAllocationsMade = false.obs;
Rxn<IranProvinceCityModel> selectedCity = Rxn();
Rxn<BroadcastPrice> broadcastPrice = Rxn<BroadcastPrice>();
GlobalKey<FormState> formKey = GlobalKey<FormState>();
TextEditingController quarantineCodeController = TextEditingController();
TextEditingController saleWeightController = TextEditingController();
TextEditingController saleCountController = TextEditingController();
TextEditingController pricePerKiloController = TextEditingController();
TextEditingController totalCostController = TextEditingController();
TextEditingController otpCodeSell = TextEditingController();
Rx<Jalali> saleDate = Jalali.now().obs;
String? key;
RxInt pricePerKilo = 0.obs;
RxInt totalCost = 0.obs;
RxInt weight = 0.obs;
RxString otpCode = ''.obs;
Rx<Resource<PaginationModel<StewardFreeSaleBar>>> salesList =
Resource<PaginationModel<StewardFreeSaleBar>>.loading().obs;
Rxn<ProductModel> selectedProduct = Rxn();
Rxn<OutProvinceCarcassesBuyer> selectedBuyer = Rxn();
RxInt saleType = 2.obs;
RxInt quotaType = 1.obs;
Rxn<Jalali> productionDate = Rxn();
Rxn<int> remainingStock = Rxn(null);
Map<String, DayData> freeProductionDateData = {};
Map<String, DayData> governmentalProductionDateData = {};
@override
void onInit() {
super.onInit();
routesName.value = [...saleLogic.routesName, 'خارج استان'].toList();
}
@override
void onReady() {
super.onReady();
getOutProvinceSales();
getBroadcastPrice();
selectedProduct.value = rootLogic.rolesProductsModel.first;
debounce(
searchedValue,
(callback) => getOutProvinceSales(),
time: Duration(milliseconds: timeDebounce),
);
setupListeners();
_updateGovernmentalProductionDateData();
_updateFreeProductionDateData();
ever(rootLogic.stewardRemainWeight, (callback) {
_updateGovernmentalProductionDateData();
_updateFreeProductionDateData();
});
ever(quotaType, (_) {
remainingStock.value = null;
productionDate.value = null;
});
debounce(pricePerKilo, time: Duration(milliseconds: 100), (callback) {
totalCost.value = callback * (weight.value);
});
ever(totalCost, (callback) {
totalCostController.text = callback.separatedByComma;
});
}
void _updateGovernmentalProductionDateData() {
List<RemainWeightDay> dates = rootLogic.stewardRemainWeight.value?.governmental ?? [];
governmentalProductionDateData = {
for (var element in dates)
element.day.toString().toJalali.formatCompactDate(): DayData(
value: element.amount?.toInt(),
),
};
}
void _updateFreeProductionDateData() {
var dates = rootLogic.stewardRemainWeight.value?.free ?? [];
freeProductionDateData = {
for (var element in dates)
element.day.toString().toJalali.formatCompactDate(): DayData(
value: element.amount?.toInt(),
),
};
}
void setSearchValue(String? value) {
searchedValue.value = value?.trim();
}
void submitFilter() {
fromDateFilter.value = fromDateFilter.value;
toDateFilter.value = toDateFilter.value;
getOutProvinceSales();
}
Future<void> getOutProvinceSales([bool isLoadingMore = false]) async {
if (isLoadingMore) {
isLoadingMoreAllocationsMade.value = true;
} else {
salesList.value = Resource<PaginationModel<StewardFreeSaleBar>>.loading();
}
await safeCall(
call: () => rootLogic.chickenRepository.getStewardFreeSaleBar(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildQueryParams(
pageSize: 20,
page: currentPage.value,
state: 'buyer-list',
search: 'filter',
role: 'Steward',
value: searchedValue.value ?? '',
fromDate: fromDateFilter.value.toDateTime(),
toDate: toDateFilter.value.toDateTime(),
),
),
onSuccess: (res) {
if ((res?.count ?? 0) == 0) {
salesList.value = Resource<PaginationModel<StewardFreeSaleBar>>.empty();
} else {
salesList.value = Resource<PaginationModel<StewardFreeSaleBar>>.success(
PaginationModel<StewardFreeSaleBar>(
count: res?.count ?? 0,
next: res?.next,
previous: res?.previous,
results: [...(salesList.value.data?.results ?? []), ...(res?.results ?? [])],
),
);
isLoadingMoreAllocationsMade.value = false;
}
},
);
}
void setupListeners() {
saleWeightController.addListener(checkSalesFormValid);
quarantineCodeController.addListener(checkSalesFormValid);
saleWeightController.addListener(() {
checkSalesFormValid();
weight.value = int.parse(saleWeightController.text.clearComma);
var res = (weight / selectedProduct.value!.weightAverage!.toInt()).round();
saleCountController.text = res.separatedByComma;
});
ever(selectedBuyer, (_) => checkSalesFormValid);
ever(selectedProduct, (_) => checkSalesFormValid);
ever(saleDate, (_) => checkSalesFormValid());
}
void checkSalesFormValid() {
isSaleSubmitButtonEnabled.value =
saleDate.value.toString().isNotEmpty &&
selectedProduct.value != null &&
selectedBuyer.value != null &&
saleWeightController.text.isNotEmpty &&
quarantineCodeController.text.isNotEmpty;
}
void setEditDataSales(StewardFreeSaleBar item) {
quarantineCodeController.text = item.clearanceCode ?? '';
saleWeightController.text = item.weightOfCarcasses?.toInt().toString() ?? '';
saleDate.value = Jalali.fromDateTime(DateTime.parse(item.date!));
selectedCity.value = IranProvinceCityModel(name: item.city);
selectedBuyer.value = buyerLogic.buyerList.value.data?.results?.firstWhere(
(element) => element.key == item.buyer?.key,
);
selectedProduct.value = rootLogic.rolesProductsModel.first;
key = item.key;
saleType.value = item.saleType == 'free' ? 2 : 1;
quotaType.value = item.quota == 'governmental' ? 1 : 2;
isSaleSubmitButtonEnabled.value = true;
productionDate.value = item.productionDate.toJalali;
pricePerKiloController.text = pricePerKilo.value.toString().separatedByComma;
totalCostController.text = totalCost.value.toString().separatedByComma;
}
Future<void> deleteStewardPurchaseOutOfProvince(String key) async {
await safeCall(
call: () => rootLogic.chickenRepository.deleteOutProvinceStewardFreeBar(
token: rootLogic.tokenService.accessToken.value!,
key: key,
),
);
}
Future<bool> createSale() async {
bool res = false;
StewardFreeSaleBarRequest requestBody = StewardFreeSaleBarRequest(
buyerKey: selectedBuyer.value?.key,
numberOfCarcasses: int.tryParse(saleCountController.text.clearComma),
weightOfCarcasses: int.tryParse(saleWeightController.text.clearComma),
date: saleDate.value.toDateTime().formattedDashedGregorian,
clearanceCode: quarantineCodeController.text,
productKey: selectedProduct.value?.key,
saleType: saleType.value == 2 ? 'free' : 'exclusive',
quota: quotaType.value == 1 ? 'governmental' : 'free',
productionDate: productionDate.value?.toDateTime().formattedDashedGregorian,
);
await safeCall(
showError: true,
call: () => rootLogic.chickenRepository.createOutProvinceStewardFreeBar(
token: rootLogic.tokenService.accessToken.value!,
body: requestBody,
),
onSuccess: (_) {
res = true;
onRefresh();
rootLogic.onRefresh();
Future.delayed(
Duration(seconds: 1),
() => defaultShowSuccessMessage("عملیات با موفقیت انجام شد"),
);
Get.back();
},
);
return res;
}
void clearSaleForm() {
quarantineCodeController.clear();
saleWeightController.clear();
saleDate.value = Jalali.now();
productionDate.value = null;
saleType.value = 2;
quotaType.value = 2;
selectedBuyer.value = null;
}
Future<bool> editSale() async {
bool res = false;
StewardFreeSaleBarRequest requestBody = StewardFreeSaleBarRequest(
numberOfCarcasses: int.tryParse(saleCountController.text.clearComma),
weightOfCarcasses: int.tryParse(saleWeightController.text.clearComma),
date: saleDate.value.toDateTime().formattedDashedGregorian,
clearanceCode: quarantineCodeController.text,
saleType: saleType.value == 2 ? 'free' : 'exclusive',
quota: quotaType.value == 1 ? 'governmental' : 'free',
key: key,
);
await safeCall(
call: () => rootLogic.chickenRepository.updateOutProvinceStewardFreeBar(
token: rootLogic.tokenService.accessToken.value!,
body: requestBody,
),
onSuccess: (_) {
res = true;
onRefresh();
Future.delayed(
Duration(seconds: 1),
() => defaultShowSuccessMessage("عملیات با موفقیت انجام شد"),
);
Get.back();
},
);
return res;
}
Future sendSaleOtpCode(StewardFreeSaleBar item) async {
StewardFreeSaleBarRequest requestBody = StewardFreeSaleBarRequest(
buyerKey: item.buyer?.key,
buyerName: item.buyer?.fullname,
buyerMobile: item.buyer?.mobile,
numberOfCarcasses: item.numberOfCarcasses,
weightOfCarcasses: item.weightOfCarcasses?.toInt(),
date: item.date,
clearanceCode: item.clearanceCode,
registerCode: otpCode.value,
saleType: item.saleType,
quota: item.quota,
role: "Steward",
key: item.key,
city: item.city,
province: item.province,
);
await safeCall(
showError: true,
call: () => rootLogic.chickenRepository.updateOutProvinceStewardFreeBar(
token: rootLogic.tokenService.accessToken.value!,
body: requestBody,
),
onSuccess: (_) {
onRefresh();
Future.delayed(
Duration(seconds: 1),
() => defaultShowSuccessMessage("عملیات با موفقیت انجام شد"),
);
Get.back();
},
);
}
void resetSubmitForm() {
selectedCity.value = null;
key = null;
}
Future<void> onRefresh() async {
toggleExpansion();
currentPage.value = 1;
resetSubmitForm();
clearSaleForm();
await rootLogic.onRefresh();
await getOutProvinceSales();
}
void toggleExpansion({int? index}) {
if (expandedListIndex.value == index || index == null) {
expandedListIndex.value = -1;
} else {
expandedListIndex.value = index;
}
}
Future<void> getBroadcastPrice() async {
safeCall(
call: () async => await rootLogic.chickenRepository.getBroadcastPrice(
token: rootLogic.tokenService.accessToken.value!,
),
onSuccess: (result) {
broadcastPrice.value = result;
},
onError: (error, stacktrace) {},
);
}
void setSaleDate(Jalali value) {
saleDate.value = value;
saleDate.refresh();
dateErrorDialog();
}
void setProductionDate(DayInfo value) {
productionDate.value = value.date;
remainingStock.value = value.remainingStock;
dateErrorDialog();
}
void dateErrorDialog() {
if ((productionDate.value?.distanceTo(saleDate.value) ?? 0) >= 1) {
saleDate.value = Jalali.now();
Future.delayed(
Duration(milliseconds: 300),
() => defaultShowErrorMessage("تاریخ تولید نمی تواند قبل از تاریخ فروش باشد"),
);
}
}
}

View File

@@ -0,0 +1,225 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/response/iran_province_city/iran_province_city_model.dart';
import 'package:rasadyar_chicken/data/models/response/out_province_carcasses_buyer/out_province_carcasses_buyer.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/root/logic.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/sale/logic.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/sales_out_of_province/logic.dart';
import 'package:rasadyar_chicken/presentation/utils/utils.dart';
import 'package:rasadyar_core/core.dart';
class WarehouseAndDistributionSalesOutOfProvinceBuyersLogic extends GetxController {
WarehouseAndDistributionRootLogic rootLogic = Get.find<WarehouseAndDistributionRootLogic>();
WarehouseAndDistributionSaleLogic get saleLogic => Get.find<WarehouseAndDistributionSaleLogic>();
WarehouseAndDistributionSalesOutOfProvinceLogic get saleOutOfProvince => Get.find<WarehouseAndDistributionSalesOutOfProvinceLogic>();
RxInt currentPage = 1.obs;
RxInt expandedListIndex = (-1).obs;
Rx<Jalali> fromDateFilter = Jalali.now().obs;
Rx<Jalali> toDateFilter = Jalali.now().obs;
RxnString searchedValue = RxnString();
RxBool isLoadingMoreAllocationsMade = false.obs;
RxBool isBuyerSubmitButtonEnabled = false.obs;
RxList<IranProvinceCityModel> cites = <IranProvinceCityModel>[].obs;
Rxn<IranProvinceCityModel> selectedProvince = Rxn();
Rxn<IranProvinceCityModel> selectedCity = Rxn();
GlobalKey<FormState> formKey = GlobalKey<FormState>();
TextEditingController buyerNameController = TextEditingController();
TextEditingController buyerLastNameController = TextEditingController();
TextEditingController buyerPhoneController = TextEditingController();
TextEditingController buyerUnitNameController = TextEditingController();
String? key;
Rx<Resource<PaginationModel<OutProvinceCarcassesBuyer>>> buyerList =
Resource<PaginationModel<OutProvinceCarcassesBuyer>>.loading().obs;
RxList<String> routesName = RxList();
@override
void onInit() {
super.onInit();
routesName.value = [...saleLogic.routesName, 'خریداران'].toList();
getOutProvinceCarcassesBuyer();
}
@override
void onReady() {
super.onReady();
selectedProvince.listen((p0) => getCites());
debounce(
searchedValue,
(callback) => getOutProvinceCarcassesBuyer(),
time: Duration(milliseconds: timeDebounce),
);
setupListeners();
}
@override
void onClose() {
buyerNameController.dispose();
buyerLastNameController.dispose();
buyerPhoneController.dispose();
buyerUnitNameController.dispose();
selectedCity.value = null;
selectedProvince.value = null;
super.onClose();
}
Future<void> getOutProvinceCarcassesBuyer([bool isLoadingMore = false]) async {
if (isLoadingMore) {
isLoadingMoreAllocationsMade.value = true;
} else {
buyerList.value = Resource<PaginationModel<OutProvinceCarcassesBuyer>>.loading();
}
if (searchedValue.value != null &&
searchedValue.value!.trim().isNotEmpty &&
currentPage.value > 1) {
currentPage.value = 1; // Reset to first page if search value is set
}
await safeCall(
call: () => rootLogic.chickenRepository.getOutProvinceCarcassesBuyer(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildQueryParams(
pageSize: 20,
page: currentPage.value,
state: 'buyer-list',
search: 'filter',
role: 'Steward',
value: searchedValue.value ?? '',
),
),
onError: (error, stackTrace) => isLoadingMoreAllocationsMade.value = false,
onSuccess: (res) {
if ((res?.count ?? 0) == 0) {
buyerList.value = Resource<PaginationModel<OutProvinceCarcassesBuyer>>.empty();
} else {
buyerList.value = Resource<PaginationModel<OutProvinceCarcassesBuyer>>.success(
PaginationModel<OutProvinceCarcassesBuyer>(
count: res?.count ?? 0,
next: res?.next,
previous: res?.previous,
results: [...(buyerList.value.data?.results ?? []), ...(res?.results ?? [])],
),
);
isLoadingMoreAllocationsMade.value = false;
}
},
);
}
void resetSubmitForm() {
buyerNameController.clear();
buyerLastNameController.clear();
buyerPhoneController.clear();
buyerUnitNameController.clear();
selectedProvince.value = null;
selectedCity.value = null;
}
Future<void> getCites() async {
await safeCall(
call: () =>
rootLogic.chickenRepository.getCity(provinceName: selectedProvince.value?.name ?? ''),
onSuccess: (result) {
if (result != null && result.isNotEmpty) {
cites.value = result;
}
},
);
}
void setupListeners() {
buyerNameController.addListener(checkBuyerFormValid);
buyerLastNameController.addListener(checkBuyerFormValid);
buyerPhoneController.addListener(checkBuyerFormValid);
buyerUnitNameController.addListener(checkBuyerFormValid);
ever(selectedProvince, (_) => checkBuyerFormValid());
ever(selectedCity, (_) => checkBuyerFormValid());
}
void checkBuyerFormValid() {
isBuyerSubmitButtonEnabled.value =
buyerNameController.text.isNotEmpty &&
buyerLastNameController.text.isNotEmpty &&
buyerPhoneController.text.isNotEmpty &&
buyerUnitNameController.text.isNotEmpty &&
selectedProvince.value != null &&
selectedCity.value != null;
}
Future<bool> createBuyer() async {
bool res = false;
if (!(formKey.currentState?.validate() ?? false)) {
return res;
}
await safeCall(
call: () async {
OutProvinceCarcassesBuyer buyer = OutProvinceCarcassesBuyer(
province: selectedProvince.value!.name,
city: selectedCity.value!.name,
firstName: buyerNameController.text,
lastName: buyerLastNameController.text,
unitName: buyerUnitNameController.text,
mobile: buyerPhoneController.text,
role: 'Steward',
);
await rootLogic.chickenRepository.createOutProvinceCarcassesBuyer(
token: rootLogic.tokenService.accessToken.value!,
body: buyer,
);
},
onSuccess: (result) {
getOutProvinceCarcassesBuyer();
resetSubmitForm();
res = true;
},
);
return res;
}
void setEditDataBuyer(OutProvinceCarcassesBuyer item) {
buyerNameController.text = item.firstName ?? '';
buyerLastNameController.text = item.lastName ?? '';
buyerUnitNameController.text = item.unitName ?? '';
buyerPhoneController.text = item.mobile ?? '';
selectedProvince.value = IranProvinceCityModel(name: item.province);
selectedCity.value = IranProvinceCityModel(name: item.city);
isBuyerSubmitButtonEnabled.value = true;
}
void setSearchValue(String? value) {
searchedValue.value = value?.trim();
}
void submitFilter() {
fromDateFilter.value = fromDateFilter.value;
toDateFilter.value = toDateFilter.value;
getOutProvinceCarcassesBuyer();
}
Future<void> onRefresh() async {
currentPage.value = 1;
await rootLogic.onRefresh();
await getOutProvinceCarcassesBuyer();
}
void toggleExpansion({int? index}) {
if (expandedListIndex.value == index || index == null) {
expandedListIndex.value = -1;
} else {
expandedListIndex.value = index;
}
}
}

View File

@@ -0,0 +1,350 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/response/iran_province_city/iran_province_city_model.dart';
import 'package:rasadyar_chicken/data/models/response/out_province_carcasses_buyer/out_province_carcasses_buyer.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_chicken/presentation/widget/filter_bottom_sheet.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class WarehouseAndDistributionSalesOutOfProvinceBuyersPage extends GetView<WarehouseAndDistributionSalesOutOfProvinceBuyersLogic> {
const WarehouseAndDistributionSalesOutOfProvinceBuyersPage({super.key});
@override
Widget build(BuildContext context) {
return ChickenBasePage(
routes: controller.routesName,
backId: stewardSecondKey,
onRefresh: controller.onRefresh,
onSearchChanged: (data) => controller.setSearchValue(data),
filteringWidget: filterBottomSheet(),
child: Stack(
children: [
Positioned.fill(
child: Column(
children: [
Container(
width: Get.width,
height: 39,
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: AppColor.greenLight,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.textColor, width: 0.5),
),
alignment: Alignment.center,
child: Text(
'لیست خریداران خارج از استان',
style: AppFonts.yekan16.copyWith(color: AppColor.mediumGreyDarkHover),
),
),
Expanded(
child: ObxValue((data) {
return RPaginatedListView(
onLoadMore: () async => controller.getOutProvinceCarcassesBuyer(true),
hasMore: data.value.data?.next != null,
listType: ListType.separated,
resource: data.value,
padding: EdgeInsets.fromLTRB(8, 8, 8, 80),
itemBuilder: (context, index) {
var item = data.value.data!.results![index];
return ObxValue((val) {
return ExpandableListItem2(
selected: val.value == index,
onTap: () => controller.toggleExpansion(index: index),
index: index,
child: itemListWidget(item),
secondChild: itemListExpandedWidget(item),
labelColor: AppColor.blueLight,
labelIcon: Assets.vec.userRaduisSvg.path,
);
}, controller.expandedListIndex);
},
itemCount: data.value.data?.results?.length ?? 0,
separatorBuilder: (context, index) => SizedBox(height: 8.h),
);
}, controller.buyerList),
),
],
),
),
Positioned(
bottom: 100,
child: RFab.add(
onPressed: () {
Get.bottomSheet(
addOrEditBuyerBottomSheet(),
isScrollControlled: true,
ignoreSafeArea: false,
).whenComplete(() => controller.resetSubmitForm());
},
),
),
],
),
);
}
Widget addOrEditBuyerBottomSheet([bool isOnEdit = false]) {
return BaseBottomSheet(
height: 600,
child: SingleChildScrollView(
child: Form(
key: controller.formKey,
child: Column(
spacing: 8,
children: [
Text(
isOnEdit ? 'ویرایش خریدار' : 'افزودن خریدار',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Column(spacing: 12, children: [_provinceWidget(), _cityWidget()]),
),
Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Column(
spacing: 12,
children: [
RTextField(
controller: controller.buyerNameController,
label: 'نام خریدار',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
),
RTextField(
controller: controller.buyerLastNameController,
label: 'نام خانوادگی خریدار',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
),
RTextField(
controller: controller.buyerPhoneController,
label: 'تلفن خریدار',
keyboardType: TextInputType.phone,
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
maxLength: 11,
validator: (value) {
if (value == null || value.isEmpty) {
return 'لطفاً شماره موبایل را وارد کنید';
}
// حذف کاماها برای اعتبارسنجی
String cleaned = value.replaceAll(',', '');
if (cleaned.length != 11) {
return 'شماره موبایل باید ۱۱ رقم باشد';
}
if (!cleaned.startsWith('09')) {
return 'شماره موبایل باید با 09 شروع شود';
}
return null;
},
),
RTextField(
controller: controller.buyerUnitNameController,
label: 'نام واحد',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
),
submitButtonWidget(isOnEdit),
],
),
),
SizedBox(),
],
),
),
),
);
}
Widget submitButtonWidget(bool isOnEdit) {
return ObxValue((data) {
return RElevated(
isFullWidth: true,
backgroundColor: AppColor.greenNormal,
text: isOnEdit ? 'ویرایش' : 'ثبت',
onPressed: data.value
? () async {
var res = await controller.createBuyer();
if (res) {
Get.back();
}
}
: null,
height: 40,
);
}, controller.isBuyerSubmitButtonEnabled);
}
Widget _provinceWidget() {
return Obx(() {
return OverlayDropdownWidget<IranProvinceCityModel>(
items: controller.rootLogic.provinces,
onChanged: (value) {
controller.selectedProvince.value = value;
print('Selected Product: ${value.name}');
},
selectedItem: controller.selectedProvince.value,
itemBuilder: (item) => Text(item.name ?? 'بدون نام'),
labelBuilder: (item) => Text(item?.name ?? 'انتخاب استان'),
);
});
}
Widget _cityWidget() {
return ObxValue((data) {
return OverlayDropdownWidget<IranProvinceCityModel>(
items: data,
onChanged: (value) {
controller.selectedCity.value = value;
print('Selected Product: ${value.name}');
},
selectedItem: controller.selectedCity.value,
itemBuilder: (item) => Text(item.name ?? 'بدون نام'),
labelBuilder: (item) => Text(item?.name ?? 'انتخاب شهر'),
);
}, controller.cites);
}
Padding itemListWidget(OutProvinceCarcassesBuyer item) {
return Padding(
padding: const EdgeInsets.only(right: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(width: 8),
Expanded(
flex: 2,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
item.buyer?.fullname ?? 'N/A',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
SizedBox(height: 2),
Text(
item.buyer?.mobile ?? 'N/A',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark),
),
],
),
),
Expanded(
flex: 2,
child: Text(
'${item.unitName}',
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
),
),
Expanded(
flex: 2,
child: Text(
'${item.buyer?.province}\n${item.buyer?.city}',
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.darkGreyDark),
),
),
],
),
);
}
Container itemListExpandedWidget(OutProvinceCarcassesBuyer item) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)),
child: Column(
spacing: 8,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
'${item.province}-${item.city}',
textAlign: TextAlign.center,
style: AppFonts.yekan16.copyWith(color: AppColor.greenDark),
),
SizedBox(),
],
),
buildRow(title: 'مشخصات خریدار', value: item.fullname ?? 'N/A'),
buildRow(title: 'نام واحد', value: item.unitName ?? 'N/A'),
buildRow(
title: 'تعداد درخواست ها',
value: '${item.requestsInfo?.numberOfRequests.separatedByCommaFa}',
),
buildRow(
title: 'حجم تقریبی',
value: '${item.requestsInfo?.totalQuantity.separatedByCommaFa}',
valueLabel: 'قطعه',
),
buildRow(
title: 'وزن',
value: '${item.requestsInfo?.totalWeight.separatedByCommaFa}',
valueLabel: 'کیلوگرم',
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 16.w,
children: [
RElevated(
text: 'ویرایش',
width: 150.w,
height: 40.h,
onPressed: () {
controller.setEditDataBuyer(item);
Get.bottomSheet(
addOrEditBuyerBottomSheet(true),
isScrollControlled: true,
).whenComplete(() => controller.resetSubmitForm());
},
textStyle: AppFonts.yekan20.copyWith(color: Colors.white),
backgroundColor: AppColor.greenNormal,
),
],
),
],
),
);
}
Widget filterBottomSheet() => filterBottomSheetWidget(
fromDate: controller.fromDateFilter,
onChangedFromDate: (jalali) => controller.fromDateFilter.value = jalali,
toDate: controller.toDateFilter,
onChangedToDate: (jalali) => controller.toDateFilter.value = jalali,
onSubmit: () => controller.submitFilter(),
);
}

View File

@@ -0,0 +1,224 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/request/steward_free_sale_bar/steward_free_sale_bar_request.dart';
import 'package:rasadyar_chicken/data/models/response/iran_province_city/iran_province_city_model.dart';
import 'package:rasadyar_chicken/data/models/response/out_province_carcasses_buyer/out_province_carcasses_buyer.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/data/models/response/steward_free_sale_bar/steward_free_sale_bar.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/root/logic.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/sale/logic.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/sales_out_of_province_buyers/logic.dart';
import 'package:rasadyar_chicken/presentation/utils/utils.dart';
import 'package:rasadyar_core/core.dart';
class WarehouseAndDistributionSalesOutOfProvinceSalesListLogic extends GetxController {
WarehouseAndDistributionRootLogic rootLogic = Get.find<WarehouseAndDistributionRootLogic>();
WarehouseAndDistributionSaleLogic saleLogic = Get.find<WarehouseAndDistributionSaleLogic>();
WarehouseAndDistributionSalesOutOfProvinceBuyersLogic buyerLogic = Get.find<WarehouseAndDistributionSalesOutOfProvinceBuyersLogic>();
RxInt selectedSegmentIndex = 0.obs;
RxBool isExpanded = false.obs;
RxInt currentPage = 1.obs;
RxBool isSaleSubmitButtonEnabled = false.obs;
RxInt expandedListIndex = (-1).obs;
Rx<Jalali> fromDateFilter = Jalali.now().obs;
Rx<Jalali> toDateFilter = Jalali.now().obs;
RxnString searchedValue = RxnString();
RxList<String> routesName = RxList();
RxBool isLoadingMoreAllocationsMade = false.obs;
Rxn<IranProvinceCityModel> selectedCity = Rxn();
//TODO add this to Di
ImagePicker imagePicker = ImagePicker();
RxInt saleType = 1.obs;
RxInt quotaType = 1.obs;
GlobalKey<FormState> formKey = GlobalKey<FormState>();
TextEditingController quarantineCodeController = TextEditingController();
TextEditingController saleWeightController = TextEditingController();
TextEditingController saleCountController = TextEditingController();
Rx<Jalali> saleDate = Jalali.now().obs;
String? key;
Rx<Resource<PaginationModel<StewardFreeSaleBar>>> salesList =
Resource<PaginationModel<StewardFreeSaleBar>>.loading().obs;
Rxn<ProductModel> selectedProduct = Rxn();
Rxn<OutProvinceCarcassesBuyer> selectedBuyer = Rxn();
@override
void onInit() {
super.onInit();
getOutProvinceSales();
}
@override
void onReady() {
super.onReady();
selectedProduct.value = rootLogic.rolesProductsModel.first;
debounce(
searchedValue,
(callback) => getOutProvinceSales(),
time: Duration(milliseconds: timeDebounce),
);
}
@override
void onClose() {
// TODO: implement onClose
super.onClose();
}
Future<void> getOutProvinceSales([bool isLoadingMore = false]) async {
if (isLoadingMore) {
isLoadingMoreAllocationsMade.value = true;
} else {
salesList.value = Resource<PaginationModel<StewardFreeSaleBar>>.loading();
}
await safeCall(
call: () => rootLogic.chickenRepository.getStewardFreeSaleBar(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildQueryParams(
pageSize: 20,
page: currentPage.value,
state: 'buyer-list',
search: 'filter',
role: 'Steward',
value: searchedValue.value ?? '',
fromDate: fromDateFilter.value.toDateTime(),
toDate: toDateFilter.value.toDateTime(),
),
),
onSuccess: (res) {
if ((res?.count ?? 0) == 0) {
salesList.value = Resource<PaginationModel<StewardFreeSaleBar>>.empty();
} else {
salesList.value = Resource<PaginationModel<StewardFreeSaleBar>>.success(
PaginationModel<StewardFreeSaleBar>(
count: res?.count ?? 0,
next: res?.next,
previous: res?.previous,
results: [...(salesList.value.data?.results ?? []), ...(res?.results ?? [])],
),
);
isLoadingMoreAllocationsMade.value = false;
}
},
);
}
void setupListeners() {
quarantineCodeController.addListener(checkSalesFormValid);
ever(selectedBuyer, (_) => checkSalesFormValid);
ever(selectedProduct, (_) => checkSalesFormValid);
ever(saleDate, (_) => checkSalesFormValid());
}
void checkSalesFormValid() {
isSaleSubmitButtonEnabled.value =
saleDate.value.toString().isNotEmpty &&
selectedProduct.value != null &&
selectedBuyer.value != null &&
saleWeightController.text.isNotEmpty &&
quarantineCodeController.text.isNotEmpty;
}
void setEditDataSales(StewardFreeSaleBar item) {
quarantineCodeController.text = item.clearanceCode ?? '';
saleWeightController.text = item.weightOfCarcasses?.toInt().toString() ?? '';
saleDate.value = Jalali.fromDateTime(DateTime.parse(item.date!));
selectedCity.value = IranProvinceCityModel(name: item.city);
selectedBuyer.value = buyerLogic.buyerList.value.data?.results?.firstWhere(
(element) => element.key == item.buyer?.key,
);
selectedProduct.value = rootLogic.rolesProductsModel.first;
key = item.key;
isSaleSubmitButtonEnabled.value = true;
}
Future<void> deleteStewardPurchaseOutOfProvince(String key) async {
//todo
/* await safeCall(
call: () => rootLogic.chickenRepository
.editStewardPurchasesOutSideOfTheProvince(
token: rootLogic.tokenService.accessToken.value!,
stewardFreeBarKey: key,
),
);*/
}
Future<bool> createSale() async {
bool res = false;
var tmpWight = int.tryParse(saleWeightController.text.clearComma);
var tmpCount = (tmpWight! / selectedProduct.value!.weightAverage!).round();
StewardFreeSaleBarRequest requestBody = StewardFreeSaleBarRequest(
buyerKey: selectedBuyer.value?.key,
numberOfCarcasses: tmpCount,
weightOfCarcasses: tmpWight,
date: saleDate.value.toDateTime().formattedDashedGregorian,
clearanceCode: quarantineCodeController.text,
productKey: selectedProduct.value?.key,
);
await safeCall(
call: () => rootLogic.chickenRepository.createOutProvinceStewardFreeBar(
token: rootLogic.tokenService.accessToken.value!,
body: requestBody,
),
onSuccess: (_) {
res = true;
},
);
return res;
}
void clearSaleForm() {
quarantineCodeController.clear();
saleWeightController.clear();
saleDate.value = Jalali.now();
selectedBuyer.value = null;
selectedProduct.value = null;
}
Future<bool> editSale() async {
bool res = false;
StewardFreeSaleBarRequest requestBody = StewardFreeSaleBarRequest(
numberOfCarcasses: 0,
weightOfCarcasses: int.tryParse(saleWeightController.text.clearComma),
date: saleDate.value.toDateTime().formattedDashedGregorian,
clearanceCode: quarantineCodeController.text,
key: key,
);
await safeCall(
call: () => rootLogic.chickenRepository.updateOutProvinceStewardFreeBar(
token: rootLogic.tokenService.accessToken.value!,
body: requestBody,
),
onSuccess: (_) {
res = true;
},
);
return res;
}
void resetSubmitForm() {
selectedCity.value = null;
selectedProduct.value = null;
key = null;
}
void toggleExpansion({int? index}) {
if (expandedListIndex.value == index || index == null) {
expandedListIndex.value = -1;
} else {
expandedListIndex.value = index;
}
}
}

View File

@@ -0,0 +1,498 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rasadyar_chicken/data/models/response/out_province_carcasses_buyer/out_province_carcasses_buyer.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/data/models/response/steward_free_sale_bar/steward_free_sale_bar.dart';
import 'package:rasadyar_chicken/presentation/routes/routes.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class WarehouseAndDistributionSalesOutOfProvinceSalesListPage extends GetView<WarehouseAndDistributionSalesOutOfProvinceSalesListLogic> {
const WarehouseAndDistributionSalesOutOfProvinceSalesListPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: ObxValue((data) {
return RPaginatedListView(
onLoadMore: () async => controller.getOutProvinceSales(true),
hasMore: data.value.data?.next != null,
listType: ListType.separated,
resource: data.value,
padding: EdgeInsets.fromLTRB(8, 8, 8, 80),
itemBuilder: (context, index) {
var item = data.value.data!.results![index];
return ObxValue((val) {
return ExpandableListItem2(
selected: val.value == index,
onTap: () => controller.toggleExpansion(),
index: index,
child: itemListWidget(item),
secondChild: itemListExpandedWidget(item, index),
labelColor: AppColor.blueLight,
labelIcon: Assets.vec.timerSvg.path,
labelIconColor: AppColor.yellowNormal2,
);
}, controller.expandedListIndex);
},
itemCount: data.value.data?.results?.length ?? 0,
separatorBuilder: (context, index) => SizedBox(height: 8.h),
);
}, controller.salesList),
floatingActionButton: Row(
children: [
RFab.add(
onPressed: () {
Get.bottomSheet(
addOrEditSaleBottomSheet(),
ignoreSafeArea: false,
isScrollControlled: true,
).whenComplete(() {
controller.clearSaleForm();
});
},
),
Spacer(),
RFab(
icon: Icon(CupertinoIcons.person_add_solid, color: Colors.white, size: 35.w),
backgroundColor: AppColor.blueNormal,
onPressed: () {
Get.toNamed(ChickenRoutes.salesOutOfProvinceBuyerSteward, id: 1);
},
),
SizedBox(width: 25),
],
),
floatingActionButtonLocation: FloatingActionButtonLocation.startFloat,
);
}
Row itemListWidget(StewardFreeSaleBar item) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(width: 12),
Expanded(
flex: 3,
child: Text(
item.date?.formattedJalaliDate ?? 'ندارد',
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
),
),
SizedBox(width: 4),
Expanded(
flex: 5,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
item.buyer?.fullname ?? 'ندارد',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
SizedBox(height: 2),
Text(
item.buyer?.mobile ?? 'ندارد',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark),
),
],
),
),
SizedBox(width: 4),
Expanded(
flex: 4,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 8,
children: [
Text(
item.buyer?.unitName ?? 'ندارد',
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
),
Text(
'${item.weightOfCarcasses?.separatedByCommaFa ?? 0}KG',
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
),
],
),
),
],
);
}
Container itemListExpandedWidget(StewardFreeSaleBar item, int index) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)),
child: Column(
spacing: 8,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
'${item.province}-${item.city}',
textAlign: TextAlign.center,
style: AppFonts.yekan16.copyWith(color: AppColor.greenDark),
),
],
),
Container(
height: 32,
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: ShapeDecoration(
color: AppColor.blueLight,
shape: RoundedRectangleBorder(
side: BorderSide(width: 1, color: AppColor.blueLightHover),
borderRadius: BorderRadius.circular(8),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
spacing: 3,
children: [
Text(
item.date?.toJalali.formatter.wN ?? 'ندارد',
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
),
Text(
'${item.date?.toJalali.formatter.d} ${item.date?.toJalali.formatter.mN ?? 'ندارد'}',
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
],
),
Text(
'${item.date?.toJalali.formatter.y}',
style: AppFonts.yekan20.copyWith(color: AppColor.textColor),
),
Text(
'${item.date?.toJalali.formatter.tHH}:${item.date?.toJalali.formatter.tMM ?? 'ندارد'}',
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
),
],
),
),
buildRow(title: 'مشخصات خریدار', value: item.buyer?.fullname ?? 'ندارد'),
buildRow(title: 'تلفن خریدار', value: item.buyer?.mobile ?? 'ندارد'),
buildRow(title: 'نام واحد', value: item.buyer?.unitName ?? 'ندارد'),
buildRow(title: 'وزن لاشه', value: '${item.weightOfCarcasses?.separatedByCommaFa}'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 16.w,
children: [
RElevated(
text: 'ویرایش',
width: 150.w,
height: 40.h,
onPressed: () {
controller.setEditDataSales(item);
Get.bottomSheet(
addOrEditSaleBottomSheet(true),
isScrollControlled: true,
).whenComplete(() {
controller.resetSubmitForm();
});
},
textStyle: AppFonts.yekan20.copyWith(color: Colors.white),
backgroundColor: AppColor.greenNormal,
),
ROutlinedElevated(
text: 'حذف',
textStyle: AppFonts.yekan20.copyWith(color: AppColor.redNormal),
width: 150.w,
height: 40.h,
onPressed: () {
buildDeleteDialog(
onConfirm: () async {
controller.toggleExpansion();
controller.deleteStewardPurchaseOutOfProvince(item.key!);
},
onRefresh: () => controller.getOutProvinceSales(),
);
},
borderColor: AppColor.redNormal,
),
],
),
],
),
);
}
Widget addOrEditSaleBottomSheet([bool isOnEdit = false]) {
return BaseBottomSheet(
height: 500.h,
child: SingleChildScrollView(
child: Form(
key: controller.formKey,
child: Column(
spacing: 16,
children: [
Text(
isOnEdit ? 'ویرایش فروش' : 'افزودن فروش',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
_productDropDown(),
Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Column(
spacing: 12,
children: [
Row(
spacing: 8,
children: [
Expanded(
child: timeFilterWidget(
date: controller.saleDate,
onChanged: (jalali) => controller.saleDate.value = jalali,
),
),
],
),
_buyerWidget(),
RTextField(
controller: controller.saleWeightController,
label: 'وزن لاشه',
keyboardType: TextInputType.number,
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
SeparatorInputFormatter(),
],
validator: (value) {
if (value == null) {
return 'لطفاً وزن لاشه را وارد کنید';
}
return null;
},
),
RTextField(
controller: controller.saleCountController,
label: 'حجم تقریبی(قطعه)',
keyboardType: TextInputType.number,
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
SeparatorInputFormatter(),
],
validator: (value) {
if (value == null) {
return 'لطفاً وزن لاشه را وارد کنید';
}
return null;
},
),
RTextField(
controller: controller.quarantineCodeController,
label: 'کد قرنطینه',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
validator: (value) {
if (value == null) {
return 'لطفاً کد قرنطینه را وارد کنید';
}
return null;
},
),
submitButtonWidget(isOnEdit),
],
),
),
SizedBox(),
],
),
),
),
);
}
Widget submitButtonWidget(bool isOnEdit) {
return ObxValue((data) {
return RElevated(
isFullWidth: true,
backgroundColor: AppColor.greenNormal,
text: isOnEdit ? 'ویرایش' : 'ثبت',
onPressed: data.value
? () async {
var res = isOnEdit ? await controller.editSale() : await controller.createSale();
if (res) {
controller.getOutProvinceSales();
controller.clearSaleForm();
Get.back();
}
}
: null,
height: 40,
);
}, controller.isSaleSubmitButtonEnabled);
}
Widget _buyerWidget() {
return Obx(() {
return OverlayDropdownWidget<OutProvinceCarcassesBuyer>(
items: controller.buyerLogic.buyerList.value.data?.results ?? [],
onChanged: (value) {
controller.selectedBuyer.value = value;
},
selectedItem: controller.selectedBuyer.value,
itemBuilder: (item) => Text(item.buyer?.fullname ?? 'بدون نام'),
labelBuilder: (item) => Text(item?.buyer?.fullname ?? 'انتخاب خریدار'),
);
});
}
Widget _productDropDown() {
return Obx(() {
return OverlayDropdownWidget<ProductModel>(
items: controller.rootLogic.rolesProductsModel,
height: 56,
hasDropIcon: false,
background: Colors.white,
onChanged: (value) {
controller.selectedProduct.value = value;
},
selectedItem: controller.selectedProduct.value,
initialValue: controller.selectedProduct.value,
itemBuilder: (item) => Text(item.name ?? 'بدون نام'),
labelBuilder: (item) => Row(
spacing: 8,
children: [
(item?.name?.contains('مرغ گرم') ?? false)
? Assets.images.chicken.image(width: 40, height: 40)
: Assets.vec.placeHolderSvg.svg(width: 40, height: 40),
Text(item?.name ?? 'انتخاب محصول'),
Spacer(),
Text(
'موجودی:${controller.rootLogic.inventoryModel.value?.totalRemainWeight.separatedByCommaFa ?? 0}',
),
],
),
);
});
}
GestureDetector timeFilterWidget({
isFrom = true,
required Rx<Jalali> date,
required Function(Jalali jalali) onChanged,
}) {
return GestureDetector(
onTap: () {
Get.bottomSheet(modalDatePicker((value) => onChanged(value)));
},
child: Container(
height: 40,
decoration: BoxDecoration(
color: AppColor.bgLight,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 1, color: AppColor.darkGreyLight),
),
padding: EdgeInsets.symmetric(horizontal: 11, vertical: 4),
child: Row(
spacing: 8,
children: [
Assets.vec.calendarSvg.svg(
width: 24,
height: 24,
colorFilter: const ColorFilter.mode(AppColor.bgDark, BlendMode.srcIn),
),
Text('تاریخ', style: AppFonts.yekan16.copyWith(color: AppColor.bgDark)),
Expanded(
child: ObxValue((data) {
return Text(
date.value.formatCompactDate(),
textAlign: TextAlign.center,
style: AppFonts.yekan16.copyWith(color: AppColor.darkGreyDark),
);
}, date),
),
],
),
),
);
}
Container modalDatePicker(ValueChanged<Jalali> onDateSelected) {
Jalali? tempPickedDate;
return Container(
height: 250,
color: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
child: Row(
children: [
SizedBox(width: 20),
RElevated(
height: 35,
width: 70,
textStyle: AppFonts.yekan14.copyWith(color: Colors.white),
onPressed: () {
onDateSelected(tempPickedDate ?? Jalali.now());
Get.back();
},
text: 'تایید',
),
Spacer(),
RElevated(
height: 35,
width: 70,
backgroundColor: AppColor.error,
textStyle: AppFonts.yekan14.copyWith(color: Colors.white),
onPressed: () {
onDateSelected(tempPickedDate ?? Jalali.now());
Get.back();
},
text: 'لغو',
),
SizedBox(width: 20),
],
),
),
Divider(height: 0, thickness: 1),
Expanded(
child: Container(
child: PersianCupertinoDatePicker(
initialDateTime: controller.saleDate.value,
mode: PersianCupertinoDatePickerMode.date,
onDateTimeChanged: (dateTime) {
tempPickedDate = dateTime;
},
),
),
),
],
),
);
}
}

View File

@@ -0,0 +1,309 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/response/broadcast_price/broadcast_price.dart';
import 'package:rasadyar_chicken/data/models/response/guild/guild_model.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/data/models/response/segmentation_model/segmentation_model.dart';
import 'package:rasadyar_chicken/data/models/response/steward_remain_weight/steward_remain_weight.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/root/logic.dart';
import 'package:rasadyar_chicken/presentation/utils/utils.dart';
import 'package:rasadyar_core/core.dart';
class WarehouseAndDistributionSegmentationLogic extends GetxController {
WarehouseAndDistributionRootLogic rootLogic = Get.find<WarehouseAndDistributionRootLogic>();
RxBool isLoadingMoreAllocationsMade = false.obs;
RxInt currentPage = 1.obs;
late List<String> routesName;
RxInt selectedSegmentIndex = 0.obs;
RxBool isExpanded = false.obs;
RxInt expandedListIndex = (-1).obs;
Rx<Jalali> fromDateFilter = Jalali.now().obs;
Rx<Jalali> toDateFilter = Jalali.now().obs;
RxnString searchedValue = RxnString();
RxInt segmentType = 1.obs;
RxInt priceType = 2.obs;
RxInt quotaType = 2.obs;
GlobalKey<FormState> formKey = GlobalKey<FormState>();
TextEditingController weightController = TextEditingController(text: '0');
RxBool isSubmitButtonEnabled = false.obs;
Rxn<GuildModel> selectedGuildModel = Rxn<GuildModel>();
Rxn<ProductModel> selectedProduct = Rxn<ProductModel>();
Rxn<SegmentationModel> selectedSegment = Rxn<SegmentationModel>();
Rxn<BroadcastPrice> broadcastPrice = Rxn<BroadcastPrice>();
Rx<Resource<PaginationModel<SegmentationModel>>> segmentationList =
Resource<PaginationModel<SegmentationModel>>.loading().obs;
RxList<GuildModel> guildsModel = <GuildModel>[].obs;
Rx<Jalali> saleDate = Jalali.now().obs;
RxInt weight = 0.obs;
Rxn<Jalali> productionDate = Rxn(null);
Rxn<int> remainingStock = Rxn(null);
Map<String, DayData> freeProductionDateData = {};
Map<String, DayData> governmentalProductionDateData = {};
@override
void onInit() {
super.onInit();
routesName = ['قطعه‌بندی'].toList();
once(rootLogic.rolesProductsModel, (callback) => selectedProduct.value = callback.first);
getAllSegmentation();
getGuilds();
ever(quotaType, (_) {
remainingStock.value = null;
productionDate.value = null;
});
_updateGovernmentalProductionDateData();
_updateFreeProductionDateData();
ever(rootLogic.stewardRemainWeight, (callback) {
_updateGovernmentalProductionDateData();
_updateFreeProductionDateData();
});
}
void _updateGovernmentalProductionDateData() {
List<RemainWeightDay> dates = rootLogic.stewardRemainWeight.value?.governmental ?? [];
governmentalProductionDateData = {
for (var element in dates)
element.day.toString().toJalali.formatCompactDate(): DayData(
value: element.amount?.toInt(),
),
};
}
void _updateFreeProductionDateData() {
var dates = rootLogic.stewardRemainWeight.value?.free ?? [];
freeProductionDateData = {
for (var element in dates)
element.day.toString().toJalali.formatCompactDate(): DayData(
value: element.amount?.toInt(),
),
};
}
@override
void onReady() {
super.onReady();
setUpListener();
}
void setSearchValue(String? value) {
searchedValue.value = value?.trim();
}
void setUpListener() {
debounce(
searchedValue,
(callback) => getAllSegmentation(),
time: Duration(milliseconds: timeDebounce),
);
everAll([selectedSegment, quotaType, priceType], (_) {
validateForm();
});
weightController.addListener(() => validateForm());
}
void setEditData(SegmentationModel item) {
selectedSegment.value = item;
weightController.text = item.weight.toString();
}
void clearForm() {
weightController.text = '0';
selectedSegment.value = null;
selectedGuildModel.value = null;
productionDate.value = null;
segmentType.value = 1;
priceType.value = 2;
quotaType.value = 1;
remainingStock.value = null;
}
void validateForm() {
var weight = int.tryParse(weightController.text.trim().clearComma) ?? 0;
var hasWeight = (remainingStock.value ?? 0) > weight;
isSubmitButtonEnabled.value =
selectedProduct.value != null &&
weightController.text.isNotEmpty &&
hasWeight &&
productionDate.value != null &&
weight > 0 &&
(segmentType.value == 1 || (segmentType.value == 2 && selectedGuildModel.value != null));
}
Future<void> getAllSegmentation([bool isLoadingMore = false]) async {
if (isLoadingMore) {
isLoadingMoreAllocationsMade.value = true;
} else {
segmentationList.value = Resource<PaginationModel<SegmentationModel>>.loading();
}
if (searchedValue.value != null &&
searchedValue.value!.trim().isNotEmpty &&
currentPage.value > 1) {
currentPage.value = 1; // Reset to first page if search value is set
}
await safeCall(
showError: true,
call: () async => await rootLogic.chickenRepository.getSegmentation(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildQueryParams(
pageSize: 20,
page: currentPage.value,
search: 'filter',
role: 'Steward',
value: searchedValue.value,
fromDate: fromDateFilter.value.toDateTime(),
toDate: toDateFilter.value.toDateTime(),
),
),
onSuccess: (result) {
if ((result?.count ?? 0) == 0) {
segmentationList.value = Resource<PaginationModel<SegmentationModel>>.empty();
} else {
segmentationList.value = Resource<PaginationModel<SegmentationModel>>.success(
PaginationModel<SegmentationModel>(
count: result?.count ?? 0,
next: result?.next,
previous: result?.previous,
results: [
...(segmentationList.value.data?.results ?? []),
...(result?.results ?? []),
],
),
);
isLoadingMoreAllocationsMade.value = false;
}
},
);
}
Future<void> deleteSegmentation(String key) async {
await safeCall(
showError: true,
showSuccess: true,
call: () => rootLogic.chickenRepository.deleteSegmentation(
token: rootLogic.tokenService.accessToken.value!,
key: key,
),
);
}
Future<bool> editSegment() async {
var res = true;
safeCall(
showError: true,
call: () async => await rootLogic.chickenRepository.editSegmentation(
token: rootLogic.tokenService.accessToken.value!,
model: SegmentationModel(
key: selectedSegment.value?.key,
weight: int.tryParse(weightController.text.clearComma) ?? 0,
productionDate: productionDate.value?.toDateTime().formattedDashedGregorian,
),
),
onSuccess: (result) {
res = true;
onRefresh();
},
onError: (error, stacktrace) {
res = false;
},
);
return res;
}
Future<bool> createSegment() async {
var res = true;
SegmentationModel segmentationModel = SegmentationModel(
productKey: selectedProduct.value?.key,
weight: int.tryParse(weightController.text.clearComma) ?? 0,
saleType: priceType.value == 1 ? 'governmental' : 'free',
quota: quotaType.value == 1 ? 'governmental' : 'free',
);
if (segmentType.value == 2) {
segmentationModel = segmentationModel.copyWith(guildKey: selectedGuildModel.value?.key);
}
segmentationModel = segmentationModel.copyWith(
productionDate: productionDate.value?.toDateTime().formattedDashedGregorian,
);
await safeCall(
showError: true,
call: () async => await rootLogic.chickenRepository.createSegmentation(
token: rootLogic.tokenService.accessToken.value!,
model: segmentationModel,
),
onSuccess: (result) async {
res = true;
isSubmitButtonEnabled.value = false;
onRefresh();
Future.delayed(
Duration(seconds: 1),
() => defaultShowSuccessMessage("قطعه‌بندی با موفقیت ثبت شد!"),
);
Get.back();
},
onError: (error, stacktrace) {
res = false;
},
);
return res;
}
Future<void> getGuilds() async {
safeCall(
call: () async => await rootLogic.chickenRepository.getGuilds(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildQueryParams(queryParams: {'all': true}, role: 'Steward'),
),
onSuccess: (result) {
if (result != null) {
guildsModel.clear();
guildsModel.addAll(result);
}
},
onError: (error, stacktrace) {},
);
}
Future<void> onRefresh() async {
toggleExpansion();
currentPage.value = 1;
await rootLogic.onRefresh();
await getAllSegmentation();
await getBroadcastPrice();
_updateFreeProductionDateData();
_updateGovernmentalProductionDateData();
}
Future<void> getBroadcastPrice() async {
safeCall(
call: () async => await rootLogic.chickenRepository.getBroadcastPrice(
token: rootLogic.tokenService.accessToken.value!,
),
onSuccess: (result) {
broadcastPrice.value = result;
if (broadcastPrice.value?.active == true) {
priceType.value = 2;
}
},
onError: (error, stacktrace) {},
);
}
void toggleExpansion({int? index}) {
if (expandedListIndex.value == index || index == null) {
expandedListIndex.value = -1;
} else {
expandedListIndex.value = index;
}
}
}

View File

@@ -0,0 +1,307 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/response/segmentation_model/segmentation_model.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/segmentation/widgets/cu_bottom_sheet.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_chicken/presentation/widget/filter_bottom_sheet.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class WarehouseAndDistributionSegmentationPage
extends GetView<WarehouseAndDistributionSegmentationLogic> {
WarehouseAndDistributionSegmentationPage({super.key});
final today = Jalali.now();
final oneDayAgo = Jalali.now().addDays(-1);
final twoDaysAgo = Jalali.now().addDays(-2);
@override
Widget build(BuildContext context) {
return ChickenBasePage(
routes: controller.routesName,
onSearchChanged: (data) => controller.setSearchValue(data),
onFilterTap: () {
Get.bottomSheet(filterBottomSheet());
},
onRefresh: controller.onRefresh,
hasBack: false,
child: Stack(
children: [
Positioned.fill(
child: ObxValue((data) {
return RPaginatedListView(
onLoadMore: () async => controller.getAllSegmentation(true),
hasMore: data.value.data?.next != null,
listType: ListType.separated,
resource: data.value,
padding: EdgeInsets.fromLTRB(8, 8, 8, 80),
itemBuilder: (context, index) {
var item = data.value.data!.results![index];
return ObxValue((val) {
return ExpandableListItem2(
selected: val.value == index,
onTap: () => controller.toggleExpansion(index: index),
index: index,
child: itemListWidget(item),
secondChild: itemListExpandedWidget(item, index),
labelColor: AppColor.blueLight,
labelIconColor: AppColor.customGrey,
labelIcon: Assets.vec.convertCubeSvg.path,
);
}, controller.expandedListIndex);
},
itemCount: data.value.data?.results?.length ?? 0,
separatorBuilder: (context, index) => SizedBox(height: 8.h),
);
}, controller.segmentationList),
),
Positioned(
right: 10,
bottom: 90.h,
child: RFab.add(
onPressed: () {
/* Get.bottomSheet(
addOrEditBottomSheet(controller),
isScrollControlled: true,
ignoreSafeArea: false,
).whenComplete(() {
controller.clearForm();
//defaultShowSuccessMessage('با موفقیت ثبت شد');
}); */
},
),
),
],
),
);
}
Widget filterBottomSheet() => filterBottomSheetWidget(
fromDate: controller.fromDateFilter,
onChangedFromDate: (jalali) => controller.fromDateFilter.value = jalali,
toDate: controller.toDateFilter,
onChangedToDate: (jalali) => controller.toDateFilter.value = jalali,
onSubmit: () => controller.getAllSegmentation(),
);
Row itemListWidget(SegmentationModel item) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(width: 12),
Expanded(
flex: 3,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 4,
children: [
Text(
item.toGuild != null ? 'قطعه‌بند' : 'مباشر',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
Text(
item.date?.formattedJalaliDate ?? 'N/A',
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
),
],
),
),
SizedBox(width: 4),
Expanded(
flex: 5,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
item.toGuild != null
? item.toGuild?.user?.fullname ?? 'N/A'
: item.buyer?.fullname ?? 'N/A',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
SizedBox(height: 2),
Text(
item.toGuild != null
? item.toGuild?.guildsName ?? 'N/A'
: item.buyer?.shop ?? 'N/A',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark),
),
],
),
),
SizedBox(width: 4),
Expanded(
flex: 2,
child: Column(
spacing: 4,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
item.weight.separatedByCommaFa.addKg,
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
style: AppFonts.yekan14Bold.copyWith(
color: AppColor.blueNormal,
),
),
Text(
item.saleType == "governmental" ? 'دولتی' : 'آزاد',
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
style: AppFonts.yekan14Bold.copyWith(
color: item.saleType == "governmental"
? AppColor.blueNormal
: AppColor.greenNormal,
),
),
],
),
),
],
);
}
Container itemListExpandedWidget(SegmentationModel item, int index) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Column(
spacing: 8,
children: [
Container(
height: 32,
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: ShapeDecoration(
color: AppColor.blueLight,
shape: RoundedRectangleBorder(
side: BorderSide(width: 1, color: AppColor.blueLightHover),
borderRadius: BorderRadius.circular(8),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
spacing: 3,
children: [
Text(
DateTimeExtensions(item.date)?.toJalali().formatter.wN ??
'N/A',
style: AppFonts.yekan14.copyWith(
color: AppColor.textColor,
),
),
Text(
'${DateTimeExtensions(item.date)?.toJalali().formatter.d} ${DateTimeExtensions(item.date)?.toJalali().formatter.mN ?? 'N/A'}',
style: AppFonts.yekan14.copyWith(
color: AppColor.blueNormal,
),
),
],
),
Text(
'${DateTimeExtensions(item.date)?.toJalali().formatter.y}',
style: AppFonts.yekan20.copyWith(color: AppColor.textColor),
),
Text(
'${DateTimeExtensions(item.date)?.toJalali().formatter.tHH}:${DateTimeExtensions(item.date)?.toJalali().formatter.tMM ?? 'N/A'}',
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
),
],
),
),
buildRow(
title: 'مشخصات خریدار',
value: item.toGuild != null
? item.toGuild?.user?.fullname ?? 'N/A'
: item.buyer?.fullname ?? 'N/A',
),
buildRow(
title: 'تلفن خریدار',
value: item.toGuild != null
? item.toGuild?.user?.mobile ?? 'N/A'
: item.buyer?.mobile ?? 'N/A',
),
buildRow(
title: 'نام واحد',
value: item.toGuild != null
? item.toGuild?.guildsName ?? 'N/A'
: item.buyer?.shop ?? 'N/A',
),
buildRow(
title: 'ماهیت',
value: item.toGuild != null ? 'قطعه‌بند' : 'مباشر',
),
buildRow(
title: 'نوع فروش',
value: item.saleType == "governmental" ? 'دولتی' : 'آزاد',
),
buildRow(
title: 'انبار فروش',
value: item.quota == "governmental" ? 'دولتی' : 'آزاد',
),
buildRow(
title: 'تاریخ تولید گوشت',
value: item.productionDate?.toJalali.formatCompactDate() ?? 'ندارد',
),
buildRow(
title: 'وزن قطعه‌بندی',
value: item.weight!.separatedByCommaFa,
valueLabel: 'کیلوگرم',
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 16.w,
children: [
RElevated(
text: 'ویرایش',
width: 150.w,
height: 40.h,
onPressed: () {
controller.setEditData(item);
/* Get.bottomSheet(
addOrEditBottomSheet(controller, isOnEdit: true),
isScrollControlled: true,
ignoreSafeArea: false,
).whenComplete(() {
controller.clearForm();
}); */
},
textStyle: AppFonts.yekan20.copyWith(color: Colors.white),
backgroundColor: AppColor.greenNormal,
),
ROutlinedElevated(
text: 'حذف',
textStyle: AppFonts.yekan20.copyWith(color: AppColor.redNormal),
width: 150.w,
height: 40.h,
onPressed: () {
buildDeleteDialog(
onConfirm: () async {
controller.toggleExpansion();
controller.deleteSegmentation(item.key!);
},
onRefresh: () => controller.onRefresh(),
);
},
borderColor: AppColor.redNormal,
),
],
),
],
),
);
}
}

View File

@@ -0,0 +1,395 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rasadyar_chicken/data/models/response/guild/guild_model.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/segmentation/logic.dart';
import 'package:rasadyar_core/core.dart';
Widget addOrEditBottomSheet(WarehouseAndDistributionSegmentationLogic controller, {bool isOnEdit = false}) {
return BaseBottomSheet(
height: isOnEdit ? 350.h : 600.h,
child: SingleChildScrollView(
child: Form(
key: controller.formKey,
child: Column(
spacing: 16,
children: [
Text(
isOnEdit ? 'ویرایش قطعه‌بندی' : 'افزودن قطعه‌بندی',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
_productDropDown(controller),
Visibility(
visible: isOnEdit == false,
child: Container(
height: 50.h,
clipBehavior: Clip.none,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Stack(
fit: StackFit.expand,
alignment: Alignment.center,
clipBehavior: Clip.none,
children: [
Positioned(
child: Container(color: Colors.white, child: Text("انبار")),
top: -10,
right: 8,
),
Obx(() {
return RadioGroup(
groupValue: controller.quotaType.value,
onChanged: (value) {
controller.quotaType.value = value ?? 0;
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: GestureDetector(
onTap: () {
controller.quotaType.value = 1;
},
child: Row(
children: [
Radio(value: 1),
Text('دولتی', style: AppFonts.yekan14),
],
),
),
),
Expanded(
child: GestureDetector(
onTap: () {
controller.quotaType.value = 2;
},
child: Row(
children: [
Radio(value: 2),
Text('آزاد', style: AppFonts.yekan14),
],
),
),
),
],
),
);
}),
],
),
),
),
Obx(() {
return MonthlyDataCalendar(
label: 'تاریخ تولید گوشت',
selectedDate: controller.productionDate.value?.formatCompactDate(),
onDateSelect: (value) {
controller.productionDate.value = value.date;
controller.remainingStock.value = value.remainingStock;
},
dayData: controller.quotaType.value == 1
? controller.governmentalProductionDateData
: controller.freeProductionDateData,
);
}),
RTextField(
controller: controller.weightController,
keyboardType: TextInputType.number,
autoValidateMode: AutovalidateMode.onUserInteraction,
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
inputFormatters: [FilteringTextInputFormatter.digitsOnly, SeparatorInputFormatter()],
validator: (value) {
if ((int.tryParse(value?.clearComma ?? '0') ?? 0) >
(controller.remainingStock.value ?? 0)) {
return 'وزن تخصیصی بیشتر از موجودی انبار است';
}
return null;
},
onChanged: (p0) {
controller.weight.value = int.tryParse(p0.clearComma) ?? 0;
},
label: 'وزن لاشه (کیلوگرم)',
),
Visibility(
visible: isOnEdit == false,
child: Container(
height: 58.h,
clipBehavior: Clip.none,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Stack(
fit: StackFit.expand,
alignment: Alignment.center,
clipBehavior: Clip.none,
children: [
Positioned(
child: Container(color: Colors.white, child: Text("فروش")),
top: -10,
right: 8,
),
Obx(() {
return RadioGroup(
groupValue: controller.priceType.value,
onChanged: (value) {
controller.priceType.value = value!;
},
child: Row(
children: [
Expanded(
child: GestureDetector(
onTap: (controller.broadcastPrice.value?.active ?? false)
? () {
controller.priceType.value = 1;
}
: null,
child: Row(
children: [
Radio(
value: 1,
enabled: controller.broadcastPrice.value?.active ?? false,
),
Text(
'قیمت مصوب',
style: AppFonts.yekan14.copyWith(
color: (controller.broadcastPrice.value?.active ?? false)
? AppColor.textColor
: AppColor.labelTextColor,
),
),
],
),
),
),
Expanded(
child: GestureDetector(
onTap: () {
controller.priceType.value = 2;
},
child: Row(
children: [
Radio(value: 2),
Text('قیمت آزاد', style: AppFonts.yekan14),
],
),
),
),
],
),
);
}),
],
),
),
),
Visibility(
visible: isOnEdit == false,
child: Column(
spacing: 12,
children: [
Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Column(
children: [
const SizedBox(height: 8),
SizedBox(
height: 40,
child: ObxValue((data) {
return RadioGroup(
onChanged: (value) {
controller.segmentType.value = value!;
controller.selectedGuildModel.value = null;
controller.selectedGuildModel.refresh();
},
groupValue: controller.segmentType.value,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Radio(value: 1),
Text('قطعه‌بندی(کاربر)', style: AppFonts.yekan14),
SizedBox(width: 12),
Radio(value: 2),
Text('تخصیص به قطعه‌بند', style: AppFonts.yekan14),
],
),
);
}, controller.priceType),
),
const SizedBox(height: 12),
ObxValue((data) {
return Visibility(
visible: data.value == 2,
child: guildsDropDown(controller),
);
}, controller.segmentType),
],
),
),
],
),
),
submitButtonWidget(controller, isOnEdit: isOnEdit),
SizedBox(),
],
),
),
),
);
}
Widget submitButtonWidget(WarehouseAndDistributionSegmentationLogic controller, {bool isOnEdit = false}) {
return ObxValue((data) {
return RElevated(
isFullWidth: true,
backgroundColor: AppColor.greenNormal,
text: isOnEdit ? 'ویرایش' : 'ثبت',
onPressed: data.value
? () async {
var res = isOnEdit
? await controller.editSegment()
: await controller.createSegment();
if (res) {
Get.back();
}
}
: null,
height: 40,
);
}, controller.isSubmitButtonEnabled);
}
Widget _productDropDown(WarehouseAndDistributionSegmentationLogic controller) {
return Obx(() {
return OverlayDropdownWidget<ProductModel>(
items: controller.rootLogic.rolesProductsModel,
height: 56,
hasDropIcon: false,
background: Colors.white,
onChanged: (value) {
controller.selectedProduct.value = value;
},
selectedItem: controller.selectedProduct.value,
initialValue: controller.selectedProduct.value,
itemBuilder: (item) => Text(item.name ?? 'بدون نام'),
labelBuilder: (item) => Row(
spacing: 8,
children: [
(item?.name?.contains('مرغ گرم') ?? false)
? Assets.images.chicken.image(width: 40, height: 40)
: Assets.vec.placeHolderSvg.svg(width: 40, height: 40),
Text(item?.name ?? 'انتخاب محصول'),
Spacer(),
ObxValue((data) {
return Visibility(visible: data.value != null, child: Text('موجودی: $data'));
}, controller.remainingStock),
],
),
);
});
}
Widget guildsDropDown(WarehouseAndDistributionSegmentationLogic controller) {
return Obx(() {
final item = controller.selectedGuildModel.value;
return OverlayDropdownWidget<GuildModel>(
key: ValueKey(item?.user?.fullname ?? ''),
items: controller.guildsModel,
onChanged: (value) {
controller.selectedGuildModel.value = value;
},
selectedItem: item,
itemBuilder: (item) => Text(
item.user != null
? '${item.steward == true ? 'مباشر' : 'صنف'} ${item.user!.fullname} (${item.user!.mobile})'
: 'بدون نام',
),
labelBuilder: (item) => Text(
item?.user != null
? '${item?.steward == true ? 'مباشر' : 'صنف'} ${item?.user!.fullname} (${item?.user!.mobile})'
: 'انتخاب مباشر/صنف',
),
);
});
}
Container modalDatePicker(WarehouseAndDistributionSegmentationLogic controller, ValueChanged<Jalali> onDateSelected) {
Jalali currentDate = Jalali.now();
Jalali? tempPickedDate;
return Container(
height: 250,
color: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
child: Row(
children: [
SizedBox(width: 20),
RElevated(
height: 35,
width: 70,
textStyle: AppFonts.yekan14.copyWith(color: Colors.white),
onPressed: () {
onDateSelected(tempPickedDate ?? Jalali.now());
Get.back();
},
text: 'تایید',
),
Spacer(),
RElevated(
height: 35,
width: 70,
backgroundColor: AppColor.error,
textStyle: AppFonts.yekan14.copyWith(color: Colors.white),
onPressed: () {
onDateSelected(tempPickedDate ?? Jalali.now());
Get.back();
},
text: 'لغو',
),
SizedBox(width: 20),
],
),
),
Divider(height: 0, thickness: 1),
Expanded(
child: Container(
child: PersianCupertinoDatePicker(
initialDateTime: controller.saleDate.value,
mode: PersianCupertinoDatePickerMode.date,
maximumDate: currentDate.addDays(3),
minimumDate: currentDate.toDateTime().subtract(Duration(days: 1)).toString().toJalali,
maximumYear: currentDate.year,
minimumYear: currentDate.year,
onDateTimeChanged: (dateTime) {
tempPickedDate = dateTime;
},
),
),
),
],
),
);
}

View File

@@ -0,0 +1,26 @@
export 'buy/logic.dart';
export 'buy/view.dart';
export 'buy_in_province/logic.dart';
export 'buy_in_province/view.dart';
export 'buy_in_province_all/logic.dart';
export 'buy_in_province_all/view.dart';
export 'buy_in_province_waiting/logic.dart';
export 'buy_in_province_waiting/view.dart';
export 'buy_out_of_province/logic.dart';
export 'buy_out_of_province/view.dart';
export 'home/logic.dart';
export 'home/view.dart';
export 'root/logic.dart';
export 'root/view.dart';
export 'sale/logic.dart';
export 'sale/view.dart';
export 'sales_in_province/logic.dart';
export 'sales_in_province/view.dart';
export 'sales_out_of_province/logic.dart';
export 'sales_out_of_province/view.dart';
export 'sales_out_of_province_buyers/logic.dart';
export 'sales_out_of_province_buyers/view.dart';
export 'sales_out_of_province_sales_list/logic.dart';
export 'sales_out_of_province_sales_list/view.dart';
export 'segmentation/logic.dart';
export 'segmentation/view.dart';

View File

@@ -3,7 +3,7 @@ import 'package:rasadyar_chicken/presentation/pages/steward/buy_in_province_all/
import 'package:rasadyar_chicken/presentation/pages/steward/buy_in_province_waiting/view.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_chicken/presentation/widget/steward/inventory_widget.dart';
import 'package:rasadyar_chicken/presentation/widget/inventory/inventory_widget.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
@@ -25,7 +25,10 @@ class BuyInProvincePage extends GetView<BuyInProvinceLogic> {
onRefresh: controller.onRefresh,
child: Column(
children: [
inventoryWidget(controller.rootLogic),
ObxValue((data) {
return InventoryWidget(inventoryModel: data.value!);
}, controller.rootLogic.inventoryModel),
segmentWidget(),
ObxValue((index) {
return Expanded(

View File

@@ -8,7 +8,8 @@ import 'package:rasadyar_chicken/data/models/response/roles_products/roles_produ
import 'package:rasadyar_chicken/data/models/response/steward_free_bar/steward_free_bar.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_chicken/presentation/widget/steward/inventory_widget.dart';
import 'package:rasadyar_chicken/presentation/widget/inventory/inventory_widget.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
@@ -32,7 +33,10 @@ class BuyOutOfProvincePage extends GetView<BuyOutOfProvinceLogic> {
Positioned.fill(
child: Column(
children: [
inventoryWidget(controller.rootLogic),
ObxValue((data) {
return InventoryWidget(inventoryModel: data.value!);
}, controller.rootLogic.inventoryModel),
ObxValue((data) {
return RPaginatedListView(
listType: ListType.separated,

View File

@@ -28,12 +28,22 @@ enum ErrorLocationType { serviceDisabled, permissionDenied, none }
class StewardRootLogic extends GetxController {
DateTime? _lastBackPressed;
RxInt currentPage = 2.obs;
List<Widget> pages = [BuyPage(), SalePage(), HomePage(), SegmentationPage(), ProfilePage()];
List<Widget> pages = [
BuyPage(),
SalePage(),
HomePage(),
SegmentationPage(),
ProfilePage(),
];
final defaultRoutes = <int, String>{0: ChickenRoutes.buySteward, 1: ChickenRoutes.saleSteward};
final defaultRoutes = <int, String>{
0: ChickenRoutes.buySteward,
1: ChickenRoutes.saleSteward,
};
RxList<ProductModel> rolesProductsModel = RxList<ProductModel>();
Rxn<WidelyUsedLocalModel> widelyUsedList = Rxn<WidelyUsedLocalModel>();
Rxn<StewardSalesInfoDashboard> stewardSalesInfoDashboard = Rxn<StewardSalesInfoDashboard>();
Rxn<StewardSalesInfoDashboard> stewardSalesInfoDashboard =
Rxn<StewardSalesInfoDashboard>();
Rxn<StewardRemainWeight> stewardRemainWeight = Rxn<StewardRemainWeight>();
late DioRemote dioRemote;
@@ -75,7 +85,9 @@ class StewardRootLogic extends GetxController {
if (widelyUsedList.value?.hasInit != true) {
//TODO
localDatasource.initWidleyUsed().then((value) => localDatasource.getAllWidely());
localDatasource.initWidleyUsed().then(
(value) => localDatasource.getAllWidely(),
);
}
}
@@ -115,6 +127,7 @@ class StewardRootLogic extends GetxController {
call: () async => await chickenRepository.getInventory(
token: tokenService.accessToken.value!,
cancelToken: _inventoryCancelToken,
role: 'Steward',
),
onSuccess: (result) {
if (result != null) {
@@ -146,7 +159,9 @@ class StewardRootLogic extends GetxController {
_provincesCancelToken = CancelToken();
try {
final res = await chickenRepository.getProvince(cancelToken: _provincesCancelToken);
final res = await chickenRepository.getProvince(
cancelToken: _provincesCancelToken,
);
if (res != null) {
provinces.clear();
provinces.value = res;
@@ -162,8 +177,9 @@ class StewardRootLogic extends GetxController {
Future<void> getRolesProducts() async {
safeCall(
call: () async =>
await chickenRepository.getRolesProducts(token: tokenService.accessToken.value!),
call: () async => await chickenRepository.getRolesProducts(
token: tokenService.accessToken.value!,
),
onSuccess: (result) {
if (result != null) {
rolesProductsModel.value = result;
@@ -190,8 +206,9 @@ class StewardRootLogic extends GetxController {
Future<void> getStewardRemainWeightData() async {
safeCall(
call: () async =>
await chickenRepository.getStewardRemainWeight(token: tokenService.accessToken.value!),
call: () async => await chickenRepository.getStewardRemainWeight(
token: tokenService.accessToken.value!,
),
onSuccess: (result) {
if (result != null) {
stewardRemainWeight.value = result;
@@ -231,7 +248,8 @@ class StewardRootLogic extends GetxController {
currentNestedKey?.currentState?.popUntil((route) => route.isFirst);
} else {
final now = DateTime.now();
if (_lastBackPressed == null || now.difference(_lastBackPressed!) > Duration(seconds: 2)) {
if (_lastBackPressed == null ||
now.difference(_lastBackPressed!) > Duration(seconds: 2)) {
_lastBackPressed = now;
Get.snackbar(
'خروج از برنامه',

View File

@@ -4,7 +4,8 @@ import 'package:rasadyar_chicken/presentation/pages/steward/sales_in_province/wi
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/utils/string_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_chicken/presentation/widget/steward/inventory_widget.dart';
import 'package:rasadyar_chicken/presentation/widget/inventory/inventory_widget.dart';
import 'package:rasadyar_core/core.dart' hide modalDatePicker;
import 'logic.dart';
@@ -27,7 +28,10 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
Positioned.fill(
child: Column(
children: [
inventoryWidget(controller.rootLogic),
ObxValue((data) {
return InventoryWidget(inventoryModel: data.value!);
}, controller.rootLogic.inventoryModel),
Expanded(
child: ObxValue((data) {
return RPaginatedListView(

View File

@@ -9,7 +9,7 @@ import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/utils/string_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_chicken/presentation/widget/filter_bottom_sheet.dart';
import 'package:rasadyar_chicken/presentation/widget/steward/inventory_widget.dart';
import 'package:rasadyar_chicken/presentation/widget/inventory/inventory_widget.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
@@ -32,7 +32,9 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
Positioned.fill(
child: Column(
children: [
inventoryWidget(controller.rootLogic),
ObxValue((data) {
return InventoryWidget(inventoryModel: data.value!);
}, controller.rootLogic.inventoryModel),
ObxValue((data) {
return RPaginatedListView(

View File

@@ -25,6 +25,8 @@ import 'package:rasadyar_chicken/presentation/pages/poultry_science/poultry_acti
import 'package:rasadyar_chicken/presentation/pages/poultry_science/root/logic.dart';
import 'package:rasadyar_chicken/presentation/pages/poultry_science/root/view.dart';
import 'package:rasadyar_chicken/presentation/pages/steward/steward.dart';
import 'package:rasadyar_chicken/presentation/pages/kill_house/warehouse_and_distribution/warehouse_and_distribution.dart'
as warehouse;
import 'package:rasadyar_chicken/presentation/routes/global_binding.dart';
import 'package:rasadyar_chicken/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/logic.dart';
@@ -274,6 +276,145 @@ sealed class ChickenPages {
}),
],
),
//region Warehouse and Distribution Pages
GetPage(
name: ChickenRoutes.initWarehouseAndDistribution,
page: () => warehouse.WarehouseAndDistributionRootPage(),
middlewares: [AuthMiddleware()],
bindings: [
GlobalBinding(),
BindingsBuilder(() {
Get.lazyPut(() => ChickenBaseLogic(), fenix: true);
Get.lazyPut(() => warehouse.WarehouseAndDistributionRootLogic());
Get.lazyPut(() => warehouse.WarehouseAndDistributionHomeLogic());
Get.lazyPut(() => warehouse.WarehouseAndDistributionBuyLogic());
Get.lazyPut(() => warehouse.WarehouseAndDistributionSaleLogic());
Get.lazyPut(
() => warehouse.WarehouseAndDistributionSegmentationLogic(),
);
}),
],
),
GetPage(
name: ChickenRoutes.homeWarehouseAndDistribution,
page: () => warehouse.WarehouseAndDistributionHomePage(),
middlewares: [AuthMiddleware()],
binding: BindingsBuilder(() {
Get.put(warehouse.WarehouseAndDistributionHomeLogic());
Get.lazyPut(() => ChickenBaseLogic());
}),
),
//sales
GetPage(
name: ChickenRoutes.saleWarehouseAndDistribution,
page: () => warehouse.WarehouseAndDistributionSalePage(),
middlewares: [AuthMiddleware()],
binding: BindingsBuilder(() {
Get.lazyPut(() => warehouse.WarehouseAndDistributionSaleLogic());
Get.lazyPut(() => ChickenBaseLogic());
Get.lazyPut(
() => warehouse.WarehouseAndDistributionSalesOutOfProvinceLogic(),
);
Get.lazyPut(
() =>
warehouse.WarehouseAndDistributionSalesOutOfProvinceBuyersLogic(),
);
Get.lazyPut(() => warehouse.WarehouseAndDistributionRootLogic());
}),
),
GetPage(
name: ChickenRoutes.salesOutOfProvinceWarehouseAndDistribution,
page: () => warehouse.WarehouseAndDistributionSalesOutOfProvincePage(),
middlewares: [AuthMiddleware()],
binding: BindingsBuilder(() {
Get.lazyPut(
() => warehouse.WarehouseAndDistributionSalesOutOfProvinceLogic(),
);
Get.lazyPut(
() =>
warehouse.WarehouseAndDistributionSalesOutOfProvinceBuyersLogic(),
);
Get.lazyPut(
() =>
warehouse.WarehouseAndDistributionSalesOutOfProvinceSalesListLogic(),
);
}),
),
GetPage(
name: ChickenRoutes.salesOutOfProvinceBuyerWarehouseAndDistribution,
page: () =>
warehouse.WarehouseAndDistributionSalesOutOfProvinceBuyersPage(),
middlewares: [AuthMiddleware()],
binding: BindingsBuilder(() {
Get.lazyPut(
() => warehouse.WarehouseAndDistributionSalesOutOfProvinceLogic(),
);
Get.lazyPut(
() =>
warehouse.WarehouseAndDistributionSalesOutOfProvinceBuyersLogic(),
);
Get.lazyPut(
() =>
warehouse.WarehouseAndDistributionSalesOutOfProvinceSalesListLogic(),
);
}),
),
GetPage(
name: ChickenRoutes.salesInProvinceWarehouseAndDistribution,
page: () => warehouse.WarehouseAndDistributionSalesInProvincePage(),
middlewares: [AuthMiddleware()],
binding: BindingsBuilder(() {
Get.lazyPut(() => ChickenBaseLogic());
Get.lazyPut(
() => warehouse.WarehouseAndDistributionSalesInProvinceLogic(),
);
}),
),
//buy
GetPage(
name: ChickenRoutes.buyWarehouseAndDistribution,
page: () => warehouse.WarehouseAndDistributionBuyPage(),
middlewares: [AuthMiddleware()],
binding: BindingsBuilder(() {
Get.lazyPut(() => ChickenBaseLogic());
Get.lazyPut(() => warehouse.WarehouseAndDistributionBuyLogic());
}),
),
GetPage(
name: ChickenRoutes.buysOutOfProvinceWarehouseAndDistribution,
page: () => warehouse.WarehouseAndDistributionBuyOutOfProvincePage(),
middlewares: [AuthMiddleware()],
binding: BindingsBuilder(() {
Get.lazyPut(() => ChickenBaseLogic());
Get.lazyPut(
() => warehouse.WarehouseAndDistributionBuyOutOfProvinceLogic(),
);
}),
),
GetPage(
name: ChickenRoutes.buysInProvinceWarehouseAndDistribution,
page: () => warehouse.WarehouseAndDistributionBuyInProvincePage(),
middlewares: [AuthMiddleware()],
binding: BindingsBuilder(() {
Get.lazyPut(() => ChickenBaseLogic());
Get.lazyPut(
() => warehouse.WarehouseAndDistributionBuyInProvinceLogic(),
);
Get.lazyPut(
() => warehouse.WarehouseAndDistributionBuyInProvinceWaitingLogic(),
);
Get.lazyPut(
() => warehouse.WarehouseAndDistributionBuyInProvinceAllLogic(),
);
}),
),
//endregion
//endregion
];
}

View File

@@ -50,5 +50,24 @@ sealed class ChickenRoutes {
static const actionKillHouse = '$_killHouse/action';
static const submitRequestKillHouse = '$actionKillHouse/submitRequest';
//region Warehouse and Distribution Routes
static const _warehouseAndDistribution = '$_killHouse/warehouseAndDistribution';
static const initWarehouseAndDistribution = '$_warehouseAndDistribution/';
static const homeWarehouseAndDistribution = '$_warehouseAndDistribution/home';
static const buyWarehouseAndDistribution = '$_warehouseAndDistribution/buy';
static const saleWarehouseAndDistribution = '$_warehouseAndDistribution/sale';
static const segmentationWarehouseAndDistribution = '$_warehouseAndDistribution/segmentation';
//buys
static const buysOutOfProvinceWarehouseAndDistribution = '$buyWarehouseAndDistribution/buyOutOfProvince';
static const buysInProvinceWarehouseAndDistribution = '$buyWarehouseAndDistribution/buyInProvince';
//sales
static const salesInProvinceWarehouseAndDistribution = '$saleWarehouseAndDistribution/SalesInProvince';
static const salesOutOfProvinceWarehouseAndDistribution = '$saleWarehouseAndDistribution/saleOutOfProvince';
static const salesOutOfProvinceBuyerWarehouseAndDistribution = '$saleWarehouseAndDistribution/saleOutOfProvinceBuyer';
//endregion
//endregion
}

View File

@@ -14,5 +14,9 @@ const int poultryThirdKey = 107;
//region kill house Keys
const int killHouseActionKey = 108;
const int killHouseWarehouseAndDistributionBuyKey = 109;
const int killHouseWarehouseAndDistributionSaleKey = 110;
//endregion

View File

@@ -0,0 +1,98 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/response/inventory/inventory_model.dart';
import 'package:rasadyar_core/core.dart';
class InventoryWidget extends StatelessWidget {
final InventoryModel? inventoryModel;
const InventoryWidget({super.key, required this.inventoryModel});
@override
Widget build(BuildContext context) {
return Container(
width: Get.width,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.symmetric(horizontal: 8.w),
child: Row(
spacing: 8.w,
children: [
_itemList(
title: 'موجودی انبار',
value: inventoryModel?.totalRemainWeight?.separatedByCommaFa,
color: const Color(0xFFEAFBFC),
),
_itemList(
title: 'مانده دولتی',
value: inventoryModel
?.totalGovernmentalRemainWeight
?.separatedByCommaFa,
color: const Color(0xFFF5ECEE),
),
_itemList(
title: 'مانده آزاد',
value: inventoryModel?.totalFreeRemainWeight?.separatedByCommaFa,
color: const Color(0xFFF1E7FF),
),
],
),
),
);
}
Widget _itemList({
required String title,
required String? value,
String? unit,
Color? color,
}) {
return Container(
width: 125.w,
height: 50.h,
clipBehavior: Clip.antiAlias,
decoration: ShapeDecoration(
color: color ?? Colors.white.withValues(alpha: 0.40),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
child: Column(
children: [
SizedBox(height: 4),
Text(
title,
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: const Color(0xFF5B5B5B)),
),
SizedBox(height: 4),
value == null || value.isEmpty
? const Center(child: CupertinoActivityIndicator())
: Padding(
padding: EdgeInsets.symmetric(horizontal: 4.w),
child: Row(
spacing: 8,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
value,
textAlign: TextAlign.right,
style: AppFonts.yekan16.copyWith(
color: const Color(0xFF5B5B5B),
),
),
Text(
unit ?? 'کیلوگرم',
textAlign: TextAlign.center,
style: AppFonts.yekan10.copyWith(
color: const Color(0xFF5B5B5B),
),
),
],
),
),
],
),
);
}
}

View File

@@ -1,80 +0,0 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/presentation/pages/steward/root/logic.dart';
import 'package:rasadyar_core/core.dart';
Widget inventoryWidget(StewardRootLogic rootLogic) {
return Container(
width: Get.width,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.symmetric(horizontal: 8.w),
child: Row(
spacing: 8.w,
children: [
ObxValue((data) {
// بررسی مقدار null بودن و نشان دادن ActivityIndicator
final value = data.value?.totalRemainWeight?.separatedByCommaFa;
return _itemList(
title: 'موجودی انبار',
value: value ?? '', // در صورت نال بودن، رشته خالی نمایش داده شود
color: const Color(0xFFEAFBFC),
);
}, rootLogic.inventoryModel),
ObxValue((data) {
final value = data.value?.totalGovernmentalRemainWeight?.separatedByCommaFa;
return _itemList(title: 'مانده دولتی', value: value ?? '',color: const Color(0xFFF5ECEE),);
}, rootLogic.stewardSalesInfoDashboard),
ObxValue((data) {
final value = data.value?.totalFreeRemainWeight?.separatedByCommaFa;
return _itemList(title: 'مانده آزاد', value: value ?? '',color: const Color(0xFFF1E7FF));
}, rootLogic.stewardSalesInfoDashboard),
],
),
),
);
}
Widget _itemList({required String title, required String? value, String? unit,Color? color}) {
return Container(
width: 125.w,
height: 50.h,
clipBehavior: Clip.antiAlias,
decoration: ShapeDecoration(
color: color??Colors.white.withValues(alpha: 0.40),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
child: Column(
children: [
SizedBox(height: 4),
Text(
title,
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: const Color(0xFF5B5B5B)),
),
SizedBox(height: 4),
value == null
? Center(child: CupertinoActivityIndicator())
: Padding(
padding: EdgeInsets.symmetric(horizontal: 4.w),
child: Row(
spacing: 8,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
value,
textAlign: TextAlign.right,
style: AppFonts.yekan16.copyWith(color: const Color(0xFF5B5B5B)),
),
Text(
unit ?? 'کیلوگرم',
textAlign: TextAlign.center,
style: AppFonts.yekan10.copyWith(color: const Color(0xFF5B5B5B)),
),
],
),
),
],
),
);
}

View File

@@ -49,6 +49,7 @@ class DioRemote implements IHttpClient {
@override
Future<DioResponse<T>> get<T>(
String path, {
CancelToken? cancelToken,
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
ProgressCallback? onReceiveProgress,
@@ -61,7 +62,7 @@ class DioRemote implements IHttpClient {
queryParameters: queryParameters,
options: Options(headers: headers),
onReceiveProgress: onReceiveProgress,
cancelToken: ApiHandler.globalCancelToken,
cancelToken: cancelToken ?? ApiHandler.globalCancelToken,
);
if (fromJsonListAsync != null && response.data is List) {
response.data = await fromJsonListAsync(response.data);

View File

@@ -21,7 +21,10 @@ class CardIcon extends StatelessWidget {
this.iconWidth = 48,
this.iconHeight = 48,
this.iconColor,
}) : assert((svgIcon != null) || (vecIcon != null), 'Either svgIcon or vecIcon must be provided');
}) : assert(
(svgIcon != null) || (vecIcon != null),
'Either svgIcon or vecIcon must be provided',
);
final String title;
final int spacing;
@@ -83,7 +86,12 @@ class CardIcon extends StatelessWidget {
Text(
title,
textAlign: TextAlign.center,
style: titleStyle ?? AppFonts.yekan16Bold.copyWith(color: titleColor, height: 1.20),
style:
titleStyle ??
AppFonts.yekan16Bold.copyWith(
color: titleColor,
height: 1.20,
),
),
],
),
@@ -114,7 +122,10 @@ class GlassMorphismCardIcon extends StatelessWidget {
this.iconHeight = 48,
this.iconColor,
this.gradient,
}) : assert((svgIcon != null) || (vecIcon != null), 'Either svgIcon or vecIcon must be provided');
}) : assert(
(svgIcon != null) || (vecIcon != null),
'Either svgIcon or vecIcon must be provided',
);
final String title;
final int spacing;
@@ -174,7 +185,10 @@ class GlassMorphismCardIcon extends StatelessWidget {
textAlign: TextAlign.center,
style:
titleStyle ??
AppFonts.yekan18Bold.copyWith(color: titleColor, height: 1.20),
AppFonts.yekan18Bold.copyWith(
color: titleColor,
height: 1.20,
),
),
),
],
@@ -208,13 +222,19 @@ class GlassMorphismCardIcon extends StatelessWidget {
fit: BoxFit.cover,
width: iconWidth.w,
height: iconHeight.h,
colorFilter: ColorFilter.mode(iconColor ?? Colors.white, BlendMode.srcIn),
colorFilter: ColorFilter.mode(
iconColor ?? Colors.white,
BlendMode.srcIn,
),
)
: SvgGenImage.vec(vecIcon!).svg(
fit: BoxFit.fill,
width: iconWidth.w,
height: iconHeight.h,
colorFilter: ColorFilter.mode(iconColor ?? Colors.white, BlendMode.srcIn),
colorFilter: ColorFilter.mode(
iconColor ?? Colors.white,
BlendMode.srcIn,
),
),
),
),
@@ -230,12 +250,22 @@ class GlassMorphismCardItem {
final String title;
final String route;
final String icon;
final int? navId;
GlassMorphismCardItem({required this.title, required this.route, required this.icon});
GlassMorphismCardItem({
required this.title,
required this.route,
required this.icon,
this.navId,
});
}
class GlassMorphismGrid extends StatelessWidget {
const GlassMorphismGrid({super.key, required this.items, required this.onTap});
const GlassMorphismGrid({
super.key,
required this.items,
required this.onTap,
});
final List<GlassMorphismCardItem> items;
final void Function(GlassMorphismCardItem item) onTap;