feat : chicken root page , inventory , sale in province

This commit is contained in:
MrM
2025-06-05 23:26:44 +03:30
parent 5849466e3b
commit 1cfcf9fa8f
68 changed files with 16615 additions and 126 deletions

View File

@@ -0,0 +1,151 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_auth/data/utils/safe_call.dart';
import 'package:rasadyar_chicken/chicken.dart';
import 'package:rasadyar_chicken/data/models/request/steward_allocation/steward_allocation_request.dart';
import 'package:rasadyar_chicken/data/models/response/bar_information/bar_information.dart';
import 'package:rasadyar_chicken/data/models/response/imported_loads_model/imported_loads_model.dart';
import 'package:rasadyar_chicken/data/models/response/waiting_arrival/waiting_arrival.dart';
import 'package:rasadyar_core/core.dart';
class EnteringTheWarehouseLogic extends GetxController {
RootLogic rootLogic = Get.find<RootLogic>();
Rxn<BarInformation> barInformation = Rxn<BarInformation>();
Rxn<WaitingArrivalModel> waitingForArrival = Rxn<WaitingArrivalModel>();
Rxn<ImportedLoadsModel> importedLoads = Rxn<ImportedLoadsModel>();
RxInt acceptType = 1.obs;
TextEditingController weightController = TextEditingController();
TextEditingController volumeController = TextEditingController();
TextEditingController weightLossController = TextEditingController();
TextEditingController authenticationCodeController = TextEditingController();
@override
void onReady() {
super.onReady();
rootLogic.getInventory();
getBarGeneralInformation();
getWaitingArrivals();
getImportedEntried();
}
Future<void> getBarGeneralInformation() async {
safeCall(
call: () async =>
await rootLogic.chickenRepository.getGeneralBarInformation(
token: rootLogic.tokenService.accessToken.value!,
),
onError: (error, stackTrace) {
eLog(error);
},
onSuccess: (result) {
if (result != null) {
barInformation.value = result;
}
},
);
}
Future<void> getWaitingArrivals() async {
safeCall(
call: () async => await rootLogic.chickenRepository.getWaitingArrivals(
token: rootLogic.tokenService.accessToken.value!,
page: 1,
),
onError: (error, stackTrace) {
eLog(error);
},
onSuccess: (result) {
if (result != null) {
waitingForArrival.value = result;
}
},
);
}
Future<void> acceptEntried(String key) async {
var request = StewardAllocationRequest(
allocationKey: key,
checkAllocation: true,
state: 'accepted',
receiverRealNumberOfCarcasses: int.parse(
volumeController.text.isNotEmpty ? volumeController.text : '0',
),
receiverRealWeightOfCarcasses: int.parse(
weightController.text.isNotEmpty ? weightController.text : '0',
),
registrationCode: acceptType.value == 1
? int.parse(
authenticationCodeController.text.isNotEmpty
? authenticationCodeController.text
: '0',
)
: null,
weightLossOfCarcasses: int.parse(
weightLossController.text.isNotEmpty ? weightLossController.text : '0',
),
).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) {
clearControllers();
getWaitingArrivals();
getBarGeneralInformation();
},
);
}
Future<void> denyEntried(String key) async {
var request = StewardAllocationRequest(
allocationKey: 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();
getBarGeneralInformation();
},
);
}
Future<void> getImportedEntried() async {
safeCall(
call: () async => await rootLogic.chickenRepository.getImportedLoadsModel(
token: rootLogic.tokenService.accessToken.value!,
page: 1,
),
onError: (error, stackTrace) {
eLog(error);
},
onSuccess: (result) {
if(result!=null){
importedLoads.value = result;
}
},
);
}
clearControllers() {
weightController.clear();
volumeController.clear();
weightLossController.clear();
authenticationCodeController.clear();
}
}

View File

@@ -0,0 +1,25 @@
extension xStringUtils on String {
get faAllocationType {
final tmp = split('_');
tmp.insert(1, '_');
if (tmp.length > 1) {
return tmp.map((e) => utilsMap[e] ?? e).join(' ');
} else {
return utilsMap[this] ?? this;
}
}
get faItem => utilsMap[this] ?? this;
}
Map<String, String> utilsMap = {
'killhouse': 'کشتارگاه',
'_': 'به',
'steward': 'مباشر',
'exclusive': 'اختصاصی',
'free': 'آزاد',
'pending': 'در انتظار',
'accepted': 'تایید شده',
'guild':'صنف'
};

View File

@@ -0,0 +1,600 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/response/bar_information/bar_information.dart';
import 'package:rasadyar_chicken/data/models/response/inventory/inventory_model.dart';
import 'package:rasadyar_chicken/data/models/response/waiting_arrival/waiting_arrival.dart';
import 'package:rasadyar_chicken/presentation/pages/entering_the_warehouse/string_utils.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class EnteringTheWarehousePage extends GetView<EnteringTheWarehouseLogic> {
EnteringTheWarehousePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: RAppBar(title: 'ورود به انبار'),
body: SingleChildScrollView(
child: Column(
children: [
inventoryWidget(),
ObxValue((data) {
return generalBarInformation(data.value);
}, controller.barInformation),
waitingForArrival(),
importedLoads(),
],
),
),
);
}
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.rootLogic.inventoryList.length,
separatorBuilder: (context, index) =>
const SizedBox(height: 8),
itemBuilder: (context, index) {
return ObxValue((expand) {
return GestureDetector(
onTap: () {
controller.rootLogic.toggleExpanded(index);
},
behavior: HitTestBehavior.opaque,
child: AnimatedContainer(
onEnd: () {
controller
.rootLogic
.inventoryExpandedList[index] = !controller
.rootLogic
.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.rootLogic.inventoryList[index],
),
),
);
}, controller.rootLogic.inventoryExpandedList);
},
),
controller.rootLogic.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('وزن خریدهای دولتی داخل استان (کیلوگرم)', '0'),
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.left,
style: AppFonts.yekan14.copyWith(
color: AppColor.darkGreyDarkHover,
),
),
),
],
),
);
}
Widget generalBarInformation(BarInformation? model) {
return Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Align(
alignment: Alignment.centerRight,
child: Text(
'اطلاعات کلی بارها',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
),
),
Container(
height: 290,
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: 8,
children: [
buildRow(
'تعداد کل بارها',
model.totalBars!.toInt().toString(),
),
buildRow(
'وزن کل بارها (کیلوگرم)',
model.totalBarsWeight!.toInt().toString(),
),
buildRow(
'تعداد کل بارهای وارد شده',
model.totalEnteredBars!.toInt().toString(),
),
buildRow(
'وزن کل بار وارد شده (کیلوگرم)',
model.totalEnteredBarsWeight!.toInt().toString(),
),
buildRow(
'تعداد کل بارهای وارد نشده',
model.totalNotEnteredBars!.toInt().toString(),
),
buildRow(
'وزن کل بار وارد نشده (کیلوگرم)',
model.totalNotEnteredKillHouseRequestsWeight!
.toInt()
.toString(),
),
buildRow(
'تعداد کل بارهای رد شده',
model.totalRejectedBars!.toInt().toString(),
),
buildRow(
' وزن کل بارهای رد شده',
model.totalRejectedBarsWeight!.toInt().toString(),
),
],
)
: const Center(child: CircularProgressIndicator()),
),
],
);
}
Widget waitingForArrival() {
return Column(
children: [
const SizedBox(height: 8),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Align(
alignment: Alignment.centerRight,
child: Text(
'موجودی انبار',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
),
),
ObxValue((data) {
if (data.value == null) {
return Container(
height: 80,
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: Center(child: CircularProgressIndicator()),
);
} else if (data.value?.results.isEmpty ?? true) {
return Container(
height: 80,
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: Center(child: Text('هیچ ورودی در انتظار نیست')),
);
} else {
return Container(
margin: const EdgeInsets.symmetric(vertical: 2),
height: 700,
padding: const EdgeInsets.all(6),
child:
ListView.separated(
padding: const EdgeInsets.all(8.0),
itemCount: data.value?.results.length ?? 0,
itemBuilder: (BuildContext context, int index) {
final result = data.value!.results[index];
return Card(
margin: const EdgeInsets.symmetric(vertical: 4.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: const BorderSide(
color: AppColor.blueNormal,
width: 1,
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildRow('ردیف', '${index + 1}'),
buildRow(
'تاریخ ثبت',
result.date!.formattedJalaliDate ?? 'N/A',
),
buildRow(
'نوع تخصیص',
result.allocationType?.faAllocationType ?? 'N/A',
),
buildRow(
'مشخصات خریدار',
result.toSteward?.user?.fullname ?? 'N/A',
),
buildRow(
'مشخصات فروشنده',
result.killHouse?.name ?? 'N/A',
),
buildRow(
'نوع فروش',
result.sellType?.faItem ?? 'N/A',
),
buildRow(
'قیمت هر کیلو',
'${result.amount ?? 0} تومان',
),
buildRow(
'قیمت کل',
'${result.totalAmount ?? 0} تومان',
),
buildRow(
'وزن تخصیصی',
'${result.weightOfCarcasses?.toInt() ?? 0} کیلوگرم',
),
buildRow('وضعیت', result.state?.faItem ?? 'N/A'),
Row(
children: [
Expanded(
child: RElevated(
text: 'تایید',
onPressed: () {
Get.bottomSheet(acceptBottomSheet(result));
},
height: 40,
),
),
SizedBox(width: 20),
Expanded(
child: RElevated(
text: 'رد',
onPressed: () {
controller.denyEntried(result.key!);
Get.back();
},
backgroundColor: AppColor.error,
height: 40,
),
),
],
),
],
),
),
);
},
separatorBuilder: (BuildContext context, int index) =>
SizedBox(height: 8),
),
);
}
}, controller.waitingForArrival)
]
);
}
Widget importedLoads() {
return Column(
children: [
const SizedBox(height: 8),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Align(
alignment: Alignment.centerRight,
child: Text(
'بارهای وارد شده',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
),
),
ObxValue((data) {
if (data.value == null) {
return Container(
height: 80,
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: Center(child: CircularProgressIndicator()),
);
}
else if (data.value?.results?.isEmpty ?? true) {
return Container(
height: 80,
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: Center(child: Text( 'هیچ بار وارد شده‌ای وجود ندارد')),
);
} else {
return Container(
margin: const EdgeInsets.symmetric(vertical: 2),
height: 700,
padding: const EdgeInsets.all(6),
child:
ListView.separated(
padding: const EdgeInsets.all(8.0),
itemCount: data.value?.results?.length ?? 0,
itemBuilder: (BuildContext context, int index) {
final result = data.value!.results![index];
return Card(
margin: const EdgeInsets.symmetric(vertical: 4.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: const BorderSide(
color: AppColor.blueNormal,
width: 1,
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildRow('ردیف', '${index + 1}'),
buildRow(
'تاریخ ثبت',
result.date!.formattedJalaliDate ?? 'N/A',
),
buildRow(
'نوع تخصیص',
result.allocationType?.faAllocationType ?? 'N/A',
),
buildRow(
'مشخصات خریدار',
'${result.toSteward?.user?.fullname} - ${result.toSteward?.guildsName}' ?? 'N/A',
),
buildRow(
'مشخصات فروشنده',
result.killHouse?.name ?? 'N/A',
),
buildRow(
'نوع فروش',
result.sellType?.faItem ?? 'N/A',
),
buildRow(
'قیمت هر کیلو',
'${result.amount ?? 0} ریال ',
),
buildRow(
'قیمت کل',
'${result.totalAmount ?? 0} ریال',
),
buildRow(
'وزن تخصیصی',
'${result.weightOfCarcasses?.toInt() ?? 0} کیلوگرم',
),
buildRow('کداحراز', result.registrationCode?.toString() ?? 'N/A'),
buildRow('وضعیت کد احراز', result.systemRegistrationCode == true ?"ارسال شده":"ارسال نشده" ?? 'N/A'),
buildRow('افت وزن(کیلوگرم)', result.weightLossOfCarcasses?.toInt().toString() ?? 'N/A'),
buildRow('وضعیت', result.receiverState?.faItem ?? 'N/A'),
],
),
),
);
},
separatorBuilder: (BuildContext context, int index) =>
SizedBox(height: 8),
),
);
}
}, controller.importedLoads)
]
);
}
Widget acceptBottomSheet(ResultModel resultModel) {
return BaseBottomSheet(
height: 500,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8,
children: [
RTextField(
controller: controller.weightController,
initText: resultModel.realWeightOfCarcasses?.toInt().toString(),
label: 'ورزن',
keyboardType: TextInputType.number,
),
const SizedBox(height: 8),
RTextField(
controller: controller.volumeController,
label: 'حجم',
keyboardType: TextInputType.number,
),
const SizedBox(height: 8),
RTextField(
controller: controller.weightLossController,
label: 'افت وزن(کیلوگرم)',
keyboardType: TextInputType.number,
),
const SizedBox(height: 8),
SizedBox(
height: 40,
child: ObxValue((data) {
return Row(
children: [
Radio(
value: 1,
groupValue: controller.acceptType.value,
onChanged: (value) {
controller.acceptType.value = value!;
},
),
Text('با کد احراز', style: AppFonts.yekan14),
SizedBox(width: 12),
Radio(
value: 2,
groupValue: controller.acceptType.value,
onChanged: (value) {
controller.acceptType.value = value!;
},
),
Text('با کد احراز', style: AppFonts.yekan14),
],
);
}, controller.acceptType),
),
const SizedBox(height: 8),
ObxValue(
(data) => Visibility(
visible: data.value == 1,
child: RTextField(
controller: controller.authenticationCodeController,
label: 'کد احراز',
keyboardType: TextInputType.number,
),
),
controller.acceptType,
),
RElevated(
text: 'تایید',
onPressed: () {
controller.acceptEntried(resultModel.key!);
Get.back();
},
),
],
),
);
}
}