refactor: update data source and repository structure by removing unused files, enhancing model integration, and adjusting import paths for better organization
This commit is contained in:
56
packages/chicken/lib/features/kill_house/action/logic.dart
Normal file
56
packages/chicken/lib/features/kill_house/action/logic.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
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 {
|
||||
List<GlassMorphismCardItem> items = [
|
||||
GlassMorphismCardItem(
|
||||
title: "ثبت درخواست",
|
||||
icon: Assets.vec.submitRequestSvg.path,
|
||||
route: ChickenRoutes.submitRequestKillHouse,
|
||||
navId: killHouseActionKey,
|
||||
),
|
||||
GlassMorphismCardItem(
|
||||
title: "انبار و توزیع",
|
||||
icon: Assets.vec.warehouseDistributionSvg.path,
|
||||
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.enterCargoInformationSvg.path,
|
||||
route: '',
|
||||
),
|
||||
GlassMorphismCardItem(
|
||||
title: "مدیریت بارها",
|
||||
icon: Assets.vec.managementBarsSvg.path,
|
||||
route: '',
|
||||
),
|
||||
];
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
// TODO: implement onReady
|
||||
super.onReady();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
// TODO: implement onClose
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
22
packages/chicken/lib/features/kill_house/action/view.dart
Normal file
22
packages/chicken/lib/features/kill_house/action/view.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
import 'logic.dart';
|
||||
|
||||
class KillHouseActionPage extends GetView<KillHouseActionLogic> {
|
||||
const KillHouseActionPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ChickenBasePage(
|
||||
isBase: true,
|
||||
child: GlassMorphismGrid(
|
||||
items: controller.items,
|
||||
onTap: (item) {
|
||||
Get.toNamed(item.route, id: item.navId);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
60
packages/chicken/lib/features/kill_house/root/logic.dart
Normal file
60
packages/chicken/lib/features/kill_house/root/logic.dart
Normal file
@@ -0,0 +1,60 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rasadyar_chicken/data/di/chicken_di.dart';
|
||||
import 'package:rasadyar_chicken/data/models/response/broadcast_price/broadcast_price.dart';
|
||||
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
|
||||
import 'package:rasadyar_chicken/data/repositories/kill_house/kill_house_repository.dart';
|
||||
import 'package:rasadyar_chicken/features/common/profile/view.dart';
|
||||
import 'package:rasadyar_chicken/presentation/routes/pages.dart';
|
||||
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 KillHouseRootLogic extends GetxController {
|
||||
RxInt currentPage = 1.obs;
|
||||
|
||||
var tokenService = Get.find<TokenStorageService>();
|
||||
|
||||
late KillHouseRepository killHouseRepository;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
killHouseRepository = diChicken.get<KillHouseRepository>();
|
||||
}
|
||||
|
||||
final pages = [
|
||||
Navigator(
|
||||
key: Get.nestedKey(killHouseActionKey),
|
||||
onGenerateRoute: (settings) {
|
||||
final page = ChickenPages.pages.firstWhere(
|
||||
(e) => e.name == settings.name,
|
||||
orElse: () => ChickenPages.pages.firstWhere(
|
||||
(e) => e.name == ChickenRoutes.actionKillHouse,
|
||||
),
|
||||
);
|
||||
|
||||
return buildRouteFromGetPage(page);
|
||||
},
|
||||
),
|
||||
Container(color: Colors.deepPurpleAccent.withAlpha(50)),
|
||||
ProfilePage(),
|
||||
];
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
// TODO: implement onReady
|
||||
super.onReady();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
// TODO: implement onClose
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
void changePage(int i) {
|
||||
currentPage.value = i;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
77
packages/chicken/lib/features/kill_house/root/view.dart
Normal file
77
packages/chicken/lib/features/kill_house/root/view.dart
Normal file
@@ -0,0 +1,77 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
import 'logic.dart';
|
||||
|
||||
class KillHouseRootPage extends GetView<KillHouseRootLogic> {
|
||||
const KillHouseRootPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ObxValue((data) {
|
||||
return ChickenBasePage(
|
||||
isBase: true,
|
||||
isFullScreen: true,
|
||||
scrollable: true,
|
||||
child: Stack(
|
||||
children: [
|
||||
IndexedStack(children: controller.pages, index: data.value),
|
||||
Positioned(
|
||||
right: 0,
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
child: RBottomNavigation(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
items: [
|
||||
RBottomNavigationItem(
|
||||
label: 'عملیات',
|
||||
icon: Assets.vec.settingSvg.path,
|
||||
isSelected: controller.currentPage.value == 0,
|
||||
onTap: () {
|
||||
/* Get.nestedKey(
|
||||
poultrySecondKey,
|
||||
)?.currentState?.popUntil((route) => route.isFirst);
|
||||
Get.nestedKey(
|
||||
poultryFirstKey,
|
||||
)?.currentState?.popUntil((route) => route.isFirst);*/
|
||||
controller.changePage(0);
|
||||
},
|
||||
),
|
||||
RBottomNavigationItem(
|
||||
label: 'خانه',
|
||||
icon: Assets.vec.homeSvg.path,
|
||||
isSelected: controller.currentPage.value == 1,
|
||||
onTap: () {
|
||||
/* Get.nestedKey(
|
||||
poultryFirstKey,
|
||||
)?.currentState?.popUntil((route) => route.isFirst);
|
||||
Get.nestedKey(
|
||||
poultryThirdKey,
|
||||
)?.currentState?.popUntil((route) => route.isFirst);*/
|
||||
controller.changePage(1);
|
||||
},
|
||||
),
|
||||
RBottomNavigationItem(
|
||||
label: 'پروفایل',
|
||||
icon: Assets.vec.profileCircleSvg.path,
|
||||
isSelected: controller.currentPage.value == 2,
|
||||
onTap: () {
|
||||
/* Get.nestedKey(
|
||||
poultryFirstKey,
|
||||
)?.currentState?.popUntil((route) => route.isFirst);
|
||||
Get.nestedKey(
|
||||
poultrySecondKey,
|
||||
)?.currentState?.popUntil((route) => route.isFirst);*/
|
||||
controller.changePage(2);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}, controller.currentPage);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
import 'logic.dart';
|
||||
|
||||
Widget addKillRequestBottomSheet(SubmitRequestKillHouseLogic controller) {
|
||||
return ObxValue(
|
||||
(data) => AnimatedContainer(
|
||||
duration: Duration(milliseconds: 300),
|
||||
height: data.value ? 680.h : 580.h,
|
||||
child: BaseBottomSheet(
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
SizedBox(width: 12),
|
||||
Text(
|
||||
"ثبت درخواست کشتار",
|
||||
style: AppFonts.yekan18Bold.copyWith(color: AppColor.iconColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(),
|
||||
SizedBox(height: 8),
|
||||
|
||||
InformationTag(
|
||||
data: InformationTagData(
|
||||
labelTitle: 'قیمت روز مرغ (${Jalali.now().formatCompactDate()})',
|
||||
labelTitleStyle: AppFonts.yekan14,
|
||||
isLoading: false,
|
||||
height: 40.h,
|
||||
value: controller.commissionPrices.chickenAveragePrice.separatedByComma.addReal,
|
||||
valueStyle: AppFonts.yekan14,
|
||||
borderColor: AppColor.greenNormal,
|
||||
radiusWidth: 1,
|
||||
valueBgColor: Colors.white,
|
||||
labelGradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [AppColor.greenLightActive, Colors.white],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
ResourceOverlayDropdown(
|
||||
height: 40.h,
|
||||
items: controller.killHouseList,
|
||||
itemBuilder: (item) => Text(item.name ?? 'بدون نام'),
|
||||
labelBuilder: (selected) => Text(selected?.name ?? 'محل کشتار'),
|
||||
onChanged: controller.setKillHouse,
|
||||
),
|
||||
|
||||
SizedBox(height: 8),
|
||||
|
||||
UnitTextField(
|
||||
controller: controller.breedCountController,
|
||||
keyboardType: TextInputType.number,
|
||||
maxLines: 1,
|
||||
minLines: 1,
|
||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly, SeparatorInputFormatter()],
|
||||
unit: 'قطعه',
|
||||
hint: 'حجم کشتار',
|
||||
initialValue: 0.separatedByComma,
|
||||
),
|
||||
|
||||
SizedBox(height: 8),
|
||||
ResourceOverlayDropdown(
|
||||
items: controller.timeFrameOfKilling,
|
||||
itemBuilder: (item) => Text(item),
|
||||
labelBuilder: (selected) => Text(selected ?? 'زمان دریافت'),
|
||||
onChanged: (selected) => controller.setTimeFrameOfKilling(selected),
|
||||
),
|
||||
|
||||
SizedBox(height: 8),
|
||||
RTextField(
|
||||
controller: controller.dateOfSlaughterTextEditor,
|
||||
hintText: 'تاریخ کشتار',
|
||||
filled: true,
|
||||
filledColor: AppColor.bgLight,
|
||||
prefixIcon: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Assets.vec.calendarSvg.svg(
|
||||
width: 16.w,
|
||||
height: 16.h,
|
||||
colorFilter: ColorFilter.mode(AppColor.bgIcon, BlendMode.srcIn),
|
||||
),
|
||||
),
|
||||
readonly: true,
|
||||
onTap: () {
|
||||
Get.bottomSheet(
|
||||
modalDatePicker(
|
||||
onDateSelected: (value) {
|
||||
controller.dateOfSlaughterTextEditor.text = value.formatCompactDate();
|
||||
controller.dateOfSlaughter = value;
|
||||
},
|
||||
),
|
||||
isScrollControlled: true,
|
||||
isDismissible: true,
|
||||
ignoreSafeArea: false,
|
||||
);
|
||||
},
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
buildAnimatedLabelContainer(controller),
|
||||
SizedBox(height: 8),
|
||||
Container(
|
||||
height: 40.h,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: AppColor.blueDark, width: 0.5),
|
||||
),
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () {
|
||||
if (controller.isAgreedUndertaking.value == false) {
|
||||
undertakingDialog(controller);
|
||||
}
|
||||
else{
|
||||
controller.toggleAgreeUndertaking(false);
|
||||
}
|
||||
},
|
||||
child: Row(
|
||||
spacing: 2,
|
||||
children: [
|
||||
ObxValue((data) {
|
||||
return Checkbox(
|
||||
value: data.value,
|
||||
onChanged: (value) {
|
||||
if (controller.isAgreedUndertaking.value == false) {
|
||||
undertakingDialog(controller);
|
||||
}
|
||||
else {
|
||||
controller.toggleAgreeUndertaking(false);
|
||||
}
|
||||
},
|
||||
);
|
||||
}, controller.isAgreedUndertaking),
|
||||
|
||||
Text(
|
||||
"با تعهدنامه موافق هستم !",
|
||||
style: AppFonts.yekan14Bold.copyWith(color: AppColor.blueDark),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Container(
|
||||
height: 40.h,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: AppColor.mediumGrey, width: 1),
|
||||
),
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () => controller.toggleAgreeSmsNotification(),
|
||||
child: Row(
|
||||
spacing: 2,
|
||||
children: [
|
||||
ObxValue((selected) {
|
||||
return Checkbox(
|
||||
value: selected.value,
|
||||
onChanged: (value) => controller.toggleAgreeSmsNotification(),
|
||||
);
|
||||
}, controller.isAgreedSmsNotification),
|
||||
Text(
|
||||
"دریافت پیامک اطلاع رسانی",
|
||||
style: AppFonts.yekan14Bold.copyWith(color: AppColor.textColor2),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Row(
|
||||
spacing: 16,
|
||||
mainAxisAlignment: .center,
|
||||
children: [
|
||||
RElevated(
|
||||
width: 160.w,
|
||||
height: 40.h,
|
||||
backgroundColor: AppColor.greenNormal,
|
||||
text: 'ثبت',
|
||||
onPressed: () async {
|
||||
await controller.submitKillRequest();
|
||||
},
|
||||
),
|
||||
|
||||
ROutlinedElevated(
|
||||
height: 40,
|
||||
text: 'انصراف',
|
||||
borderColor: AppColor.redNormal,
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
controller.isBreedWeightSelected,
|
||||
);
|
||||
}
|
||||
|
||||
void undertakingDialog(SubmitRequestKillHouseLogic controller) {
|
||||
Get.dialog(
|
||||
AlertDialog(
|
||||
title: Text("تعهد نامه", textAlign: TextAlign.center),
|
||||
titleTextStyle: AppFonts.yekan20.copyWith(color: AppColor.textColor3),
|
||||
content: Column(
|
||||
mainAxisSize: .min,
|
||||
spacing: 10,
|
||||
children: [
|
||||
Text(
|
||||
"اینجانب ${controller.baseLogic.userProfile.value.data?.fullname} موافقت خود را نسبت به موارد ذکر شده اعلام می نمایم.",
|
||||
style: AppFonts.yekan13.copyWith(color: AppColor.textColor3),
|
||||
),
|
||||
Text(
|
||||
"✅ بر اساس این توافق نامه در صورت لغو کشتار جریمه خواهم شد.",
|
||||
style: AppFonts.yekan13.copyWith(color: AppColor.textColor3),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
Row(
|
||||
spacing: 10,
|
||||
children: [
|
||||
Expanded(
|
||||
child: RElevated(
|
||||
text: 'موافقم',
|
||||
height: 32.h,
|
||||
onPressed: () {
|
||||
controller.toggleAgreeUndertaking(true);
|
||||
Get.back();
|
||||
},
|
||||
textStyle: AppFonts.yekan20Bold.copyWith(color: Colors.white),
|
||||
backgroundColor: AppColor.greenNormal,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ROutlinedElevated(
|
||||
text: 'رد',
|
||||
textStyle: AppFonts.yekan20.copyWith(color: AppColor.redNormal),
|
||||
height: 32.h,
|
||||
onPressed: () {
|
||||
controller.toggleAgreeUndertaking(false);
|
||||
Get.back();
|
||||
},
|
||||
borderColor: AppColor.redNormal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildAnimatedLabelContainer(SubmitRequestKillHouseLogic controller) {
|
||||
return ObxValue((data) {
|
||||
return AnimatedCrossFade(
|
||||
firstChild: GestureDetector(
|
||||
onTap: () {
|
||||
controller.toggleBreedWeightSelection();
|
||||
},
|
||||
child: Container(
|
||||
height: 40.h,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: AppColor.mediumGrey, width: 0.5),
|
||||
),
|
||||
child: Row(
|
||||
spacing: 7,
|
||||
children: [
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Switch(
|
||||
value: data.value,
|
||||
onChanged: (data) => controller.toggleBreedWeightSelection(),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"تعیین نژاد / وزن مرغ",
|
||||
style: AppFonts.yekan14Bold.copyWith(color: AppColor.textColor2),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
secondChild: SizedBox(
|
||||
height: 140.h,
|
||||
child: Stack(
|
||||
fit: StackFit.passthrough,
|
||||
children: [
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
height: 121.h,
|
||||
padding: EdgeInsets.fromLTRB(8.r, 18.r, 8.r, 8.r),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: AppColor.mediumGrey, width: (0.5).w),
|
||||
),
|
||||
child: Column(
|
||||
spacing: 8,
|
||||
children: [
|
||||
ResourceOverlayDropdown(
|
||||
items: controller.chickenBreedList,
|
||||
itemBuilder: (item) => Text(item),
|
||||
labelBuilder: (selected) => Text(selected ?? 'نژاد مرغ'),
|
||||
onChanged: (selected) => controller.setChickenBreed(selected),
|
||||
),
|
||||
|
||||
RTextField(
|
||||
controller: controller.chickenWeight,
|
||||
label: ' وزن مرغ (کیلوگرم) ',
|
||||
filled: true,
|
||||
filledColor: AppColor.bgLight,
|
||||
keyboardType: TextInputType.number,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.digitsOnly,
|
||||
SeparatorInputFormatter(),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 7,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
controller.toggleBreedWeightSelection();
|
||||
},
|
||||
child: Container(
|
||||
height: 30.h,
|
||||
padding: EdgeInsets.symmetric(horizontal: 4.w, vertical: 4.h),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: AppColor.mediumGrey, width: 0.5),
|
||||
),
|
||||
child: Row(
|
||||
spacing: 7,
|
||||
children: [
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Switch(
|
||||
value: data.value,
|
||||
onChanged: (_) => controller.toggleBreedWeightSelection(),
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"تعیین نژاد / وزن مرغ",
|
||||
style: AppFonts.yekan14Bold.copyWith(color: AppColor.textColor2),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
crossFadeState: data.value ? CrossFadeState.showSecond : CrossFadeState.showFirst,
|
||||
duration: Duration(milliseconds: 500),
|
||||
);
|
||||
}, controller.isBreedWeightSelected);
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/request/kill_request_response.dart';
|
||||
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/chicken_commission_prices/chicken_commission_prices.dart';
|
||||
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/features/kill_house/root/logic.dart';
|
||||
import 'package:rasadyar_chicken/presentation/widget/base_page/logic.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
class SubmitRequestKillHouseLogic extends GetxController {
|
||||
ChickenBaseLogic baseLogic = Get.find<ChickenBaseLogic>();
|
||||
RxList<String> routesName = ["عملیات", "ثبت درخواست کشتار"].obs;
|
||||
late KillHouseRootLogic rootLogic;
|
||||
|
||||
RxInt expandedItemIndex = RxInt(-1);
|
||||
Rx<Jalali> fromDateFilter = Jalali.now().obs;
|
||||
Rx<Jalali> toDateFilter = Jalali.now().obs;
|
||||
RxnString searchedValue = RxnString();
|
||||
|
||||
RxBool isBreedWeightSelected = false.obs;
|
||||
|
||||
TextEditingController breedCountController = TextEditingController();
|
||||
TextEditingController dateOfSlaughterTextEditor = TextEditingController();
|
||||
Jalali dateOfSlaughter = Jalali.now();
|
||||
TextEditingController chickenWeight = TextEditingController();
|
||||
|
||||
Resource<List<String>> timeFrameOfKilling = Resource.success([
|
||||
'12 - 14',
|
||||
'14 - 16',
|
||||
'16 - 18',
|
||||
'18 - 20',
|
||||
'20 - 22',
|
||||
'22 - 24',
|
||||
]);
|
||||
|
||||
RxString timeFrameOfKillingSelected = ''.obs;
|
||||
|
||||
Resource<List<String>> chickenBreedList = Resource.success([
|
||||
'آرین',
|
||||
'راس',
|
||||
'آربراکوز (آیلاس)',
|
||||
'کاب',
|
||||
'هوبارد',
|
||||
'ترکیبی',
|
||||
'وارداتی',
|
||||
]);
|
||||
|
||||
RxString chickenBreedSelected = ''.obs;
|
||||
RxBool isAgreedUndertaking = false.obs;
|
||||
RxBool isAgreedSmsNotification = false.obs;
|
||||
|
||||
KillHouseResponse? selectedKillHouse;
|
||||
late Resource<List<KillHouseResponse>> killHouseList;
|
||||
late ChickenCommissionPrices commissionPrices;
|
||||
|
||||
Rx<Resource<List<listModel.KillRequestList>>> killRequestList = Rx(
|
||||
Resource.initial(),
|
||||
);
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
rootLogic = Get.find<KillHouseRootLogic>();
|
||||
|
||||
getCommissionPrice();
|
||||
getKillHouseList();
|
||||
getListOfKillRequests();
|
||||
dateOfSlaughterTextEditor.text = Jalali.now().formatCompactDate();
|
||||
dateOfSlaughter = Jalali.now();
|
||||
chickenWeight.text = '2.7';
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
// TODO: implement onClose
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
void onRefresh() {
|
||||
getCommissionPrice();
|
||||
getKillHouseList();
|
||||
getListOfKillRequests();
|
||||
}
|
||||
|
||||
void toggleExpandedItem(int index) {
|
||||
if (expandedItemIndex.value == index) {
|
||||
expandedItemIndex.value = -1;
|
||||
} else {
|
||||
expandedItemIndex.value = index;
|
||||
}
|
||||
}
|
||||
|
||||
void toggleBreedWeightSelection() {
|
||||
isBreedWeightSelected.value = !isBreedWeightSelected.value;
|
||||
}
|
||||
|
||||
void clearPage() {
|
||||
expandedItemIndex.value = -1;
|
||||
isBreedWeightSelected.value = false;
|
||||
isAgreedUndertaking.value = false;
|
||||
isAgreedSmsNotification.value = false;
|
||||
breedCountController.clear();
|
||||
dateOfSlaughter = Jalali.now();
|
||||
dateOfSlaughterTextEditor.text = Jalali.now().formatCompactDate();
|
||||
chickenWeight.text = '2.7';
|
||||
timeFrameOfKillingSelected.value = '';
|
||||
chickenBreedSelected.value = '';
|
||||
}
|
||||
|
||||
void setKillHouse(KillHouseResponse killHouse) {
|
||||
selectedKillHouse = killHouse;
|
||||
iLog(selectedKillHouse?.key);
|
||||
}
|
||||
|
||||
void setTimeFrameOfKilling(String timeFrame) {
|
||||
timeFrameOfKillingSelected.value = timeFrame;
|
||||
}
|
||||
|
||||
void setChickenBreed(String breed) {
|
||||
chickenBreedSelected.value = breed;
|
||||
}
|
||||
|
||||
void toggleAgreeUndertaking(bool item) {
|
||||
isAgreedUndertaking.value = item;
|
||||
}
|
||||
|
||||
void toggleAgreeSmsNotification() {
|
||||
isAgreedSmsNotification.value = !isAgreedSmsNotification.value;
|
||||
}
|
||||
|
||||
Future<void> getKillHouseList() async {
|
||||
await safeCall(
|
||||
call: () => rootLogic.killHouseRepository.getKillHouseList(
|
||||
token: rootLogic.tokenService.accessToken.value ?? '',
|
||||
),
|
||||
onSuccess: (result) => killHouseList = Resource.success(result ?? []),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> getCommissionPrice() async {
|
||||
await safeCall(
|
||||
call: () => rootLogic.killHouseRepository.getCommissionPrice(
|
||||
token: rootLogic.tokenService.accessToken.value ?? '',
|
||||
),
|
||||
onSuccess: (result) => commissionPrices =
|
||||
result ?? ChickenCommissionPrices(chickenAveragePrice: 0),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> submitKillRequest() async {
|
||||
KillRequestResponse request = KillRequestResponse(
|
||||
killCapacity: int.parse(breedCountController.text),
|
||||
reciveTime: timeFrameOfKillingSelected.value,
|
||||
reciveDate: dateOfSlaughter
|
||||
.toDateTime()
|
||||
.formattedGregorianDateWithoutMillisecond,
|
||||
lowWeight: false,
|
||||
highWeight: false,
|
||||
indexWeight: double.parse(chickenWeight.text),
|
||||
chickenBreed: chickenBreedSelected.value,
|
||||
cash: true,
|
||||
credit: false,
|
||||
smsPayment: isAgreedSmsNotification.value,
|
||||
killHouseKey: selectedKillHouse?.key,
|
||||
killerKillHouseKey: null,
|
||||
role: 'KillHouse',
|
||||
);
|
||||
await safeCall(
|
||||
showError: true,
|
||||
|
||||
call: () => rootLogic.killHouseRepository.submitKillHouseRequest(
|
||||
token: rootLogic.tokenService.accessToken.value ?? '',
|
||||
data: request,
|
||||
),
|
||||
onSuccess: (result) {
|
||||
onRefresh();
|
||||
Get.back();
|
||||
Future.delayed(
|
||||
Duration(seconds: 3),
|
||||
() => defaultShowSuccessMessage("عملیات با موفقیت انجام شد"),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> getListOfKillRequests() async {
|
||||
await safeCall(
|
||||
showError: true,
|
||||
call: () => rootLogic.killHouseRepository.getListKillRequest(
|
||||
token: rootLogic.tokenService.accessToken.value ?? '',
|
||||
queryParameters: buildRawQueryParams(
|
||||
role: 'KillHouse',
|
||||
fromDate: fromDateFilter.value.toDateTime(),
|
||||
toDate: toDateFilter.value.toDateTime(),
|
||||
),
|
||||
),
|
||||
onSuccess: (result) {
|
||||
if (result == null || result.isEmpty) {
|
||||
killRequestList.value = Resource.empty();
|
||||
return;
|
||||
}
|
||||
killRequestList.value = Resource.success(result);
|
||||
},
|
||||
onError: (error, stackTrace) {
|
||||
killRequestList.value = Resource.error(error);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> deleteRequest(int id) async {
|
||||
await safeCall(
|
||||
showError: true,
|
||||
|
||||
call: () => rootLogic.killHouseRepository.deleteKillRequest(
|
||||
token: rootLogic.tokenService.accessToken.value ?? '',
|
||||
requestId: id,
|
||||
),
|
||||
onSuccess: (result) {
|
||||
onRefresh();
|
||||
Get.back();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
import 'package:flutter/material.dart';
|
||||
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/presentation/utils/nested_keys_utils.dart';
|
||||
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
import 'add_request_bottom_sheet.dart';
|
||||
import 'logic.dart';
|
||||
|
||||
class SubmitRequestKillHousePage extends GetView<SubmitRequestKillHouseLogic> {
|
||||
const SubmitRequestKillHousePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ChickenBasePage(
|
||||
hasBack: true,
|
||||
hasFilter: true,
|
||||
hasSearch: true,
|
||||
onBackTap: () => Get.back(id: killHouseActionKey),
|
||||
onSearchChanged: (data) {
|
||||
//Todo
|
||||
},
|
||||
onRefresh: () async => controller.onRefresh(),
|
||||
routesWidget: ContainerBreadcrumb(rxRoutes: controller.routesName),
|
||||
child: Stack(
|
||||
fit: .expand,
|
||||
children: [
|
||||
Positioned.fill(
|
||||
right: 13,
|
||||
left: 14,
|
||||
child: Obx(() {
|
||||
return RListView.separated(
|
||||
itemCount: controller.killRequestList.value.data?.length ?? 0,
|
||||
itemBuilder: (context, index) {
|
||||
var item = controller.killRequestList.value.data![index];
|
||||
return ObxValue((data) {
|
||||
return ExpandableListItem2(
|
||||
index: index,
|
||||
child: itemListWidget(item),
|
||||
secondChild: itemListExpandedWidget(item),
|
||||
onTap: () => controller.toggleExpandedItem(index),
|
||||
selected: data.value == index,
|
||||
labelColor: AppColor.blueLight,
|
||||
labelIcon: Assets.vec.virtualSvg.path,
|
||||
);
|
||||
}, controller.expandedItemIndex);
|
||||
},
|
||||
separatorBuilder: (context, index) => SizedBox(height: 8),
|
||||
resource: controller.killRequestList.value,
|
||||
);
|
||||
}),
|
||||
),
|
||||
|
||||
Positioned(
|
||||
right: 8,
|
||||
bottom: 92,
|
||||
child: RFab.add(
|
||||
onPressed: () {
|
||||
Get.bottomSheet(
|
||||
isScrollControlled: true,
|
||||
addKillRequestBottomSheet(controller),
|
||||
).then((value) {
|
||||
controller.clearPage();
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Row itemListWidget(listModel.KillRequestList item) {
|
||||
return Row(
|
||||
children: [
|
||||
SizedBox(width: 30),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
item.killHouse?.name ?? 'بدون نام',
|
||||
style: AppFonts.yekan14Bold.copyWith(color: AppColor.blueNormal),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
item.createDate?.toJalali.formatCompactDate() ?? "-",
|
||||
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark),
|
||||
),
|
||||
],
|
||||
),
|
||||
Spacer(),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'درخواست ${item.killCapacity}'.addCountEXT,
|
||||
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
'تعداد مورد تایید 150 قطعه',
|
||||
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
Spacer(),
|
||||
Assets.vec.scanSvg.svg(
|
||||
width: 32.w,
|
||||
height: 32.h,
|
||||
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Container itemListExpandedWidget(listModel.KillRequestList item) {
|
||||
Jalali date = item.createDate.toJalali;
|
||||
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.killHouse?.name ?? 'بدون نام',
|
||||
textAlign: TextAlign.center,
|
||||
style: AppFonts.yekan16.copyWith(color: AppColor.greenDark),
|
||||
),
|
||||
Spacer(),
|
||||
//todo
|
||||
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(
|
||||
date.formatter.wN,
|
||||
style: AppFonts.yekan14.copyWith(
|
||||
color: AppColor.textColor,
|
||||
),
|
||||
),
|
||||
|
||||
Text(
|
||||
'${date.formatter.d} ${date.formatter.mN ?? 'N/A'}',
|
||||
style: AppFonts.yekan14.copyWith(
|
||||
color: AppColor.blueNormal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
Text(
|
||||
date.formatter.y,
|
||||
style: AppFonts.yekan20.copyWith(color: AppColor.textColor),
|
||||
),
|
||||
|
||||
Text(
|
||||
'${date.formatter.tHH}:${date.formatter.tMM ?? 'N/A'}',
|
||||
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
buildRow(
|
||||
title: 'تعداد درخواست اولیه',
|
||||
value: item.killCapacity.separatedByComma.addCountEXT,
|
||||
),
|
||||
//todo
|
||||
buildRow(
|
||||
title: 'تعداد مورد تایید',
|
||||
value: item.numberOfAllocated.separatedByComma.addCountEXT,
|
||||
),
|
||||
buildRow(title: 'زمان دریافت', value: item.reciveTime ?? '-'),
|
||||
buildRow(
|
||||
title: 'تاریخ درخواستی کشتار',
|
||||
value: item.reciveDate.toJalali.formatCompactDate(),
|
||||
),
|
||||
ROutlinedElevated(
|
||||
text: 'حذف',
|
||||
height: 40.h,
|
||||
textStyle: AppFonts.yekan20.copyWith(color: AppColor.redNormal),
|
||||
isFullWidth: true,
|
||||
onPressed: () {
|
||||
buildWarningDialog(
|
||||
title: 'اخطار',
|
||||
middleText: 'آیا از حذف شدن این مورد اطمینان دارید؟',
|
||||
onConfirm: () async {
|
||||
controller.deleteRequest(item.id!);
|
||||
},
|
||||
onRefresh: () async {
|
||||
controller.onRefresh();
|
||||
},
|
||||
);
|
||||
},
|
||||
borderColor: AppColor.redNormal,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/buy/logic.dart';
|
||||
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/buy_in_province_entered/logic.dart';
|
||||
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/buy_in_province_waiting/logic.dart';
|
||||
import 'package:rasadyar_chicken/features/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;
|
||||
|
||||
WarehouseAndDistributionBuyInProvinceEnteredLogic buyAllLogic =
|
||||
Get.find<WarehouseAndDistributionBuyInProvinceEnteredLogic>();
|
||||
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.getKillHouseBars();
|
||||
} else {
|
||||
buyAllLogic.getkillHouseBars();
|
||||
}
|
||||
}
|
||||
|
||||
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.getKillHouseBars(),
|
||||
buyAllLogic.getkillHouseBars(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/buy_in_province_entered/view.dart';
|
||||
import 'package:rasadyar_chicken/features/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: [
|
||||
Obx(() {
|
||||
final listInventory = [
|
||||
InventoryItemData(
|
||||
title: 'موجودی انبار',
|
||||
value: controller
|
||||
.rootLogic
|
||||
.rolesProduct
|
||||
.value
|
||||
?.totalRemainWeight
|
||||
?.separatedByCommaFa,
|
||||
color: const Color(0xFFEAFBFC),
|
||||
),
|
||||
InventoryItemData(
|
||||
title: 'مانده دولتی',
|
||||
value: controller
|
||||
.rootLogic
|
||||
.salesInfoDashboard
|
||||
.value
|
||||
?.totalGovernmentalRemainWeight
|
||||
?.separatedByCommaFa,
|
||||
color: const Color(0xFFF5ECEE),
|
||||
),
|
||||
InventoryItemData(
|
||||
title: 'مانده آزاد',
|
||||
value: controller
|
||||
.rootLogic
|
||||
.salesInfoDashboard
|
||||
.value
|
||||
?.totalFreeRemainWeight
|
||||
?.separatedByCommaFa,
|
||||
color: const Color(0xFFF1E7FF),
|
||||
),
|
||||
];
|
||||
|
||||
return InventoryWidget(inventoryModel: listInventory);
|
||||
}),
|
||||
|
||||
segmentWidget(),
|
||||
ObxValue((index) {
|
||||
return Expanded(
|
||||
child: index.value == 0
|
||||
? WarehouseAndDistributionBuyInProvinceWaitingPage()
|
||||
: WarehouseAndDistributionBuyInProvinceEnteredPage(),
|
||||
);
|
||||
}, 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),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.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/features/kill_house/warehouse_and_distribution/root/logic.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
class WarehouseAndDistributionBuyInProvinceEnteredLogic 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<KillHouseBarsResponse>>> enteredBars =
|
||||
Resource<PaginationModel<KillHouseBarsResponse>>.loading().obs;
|
||||
|
||||
TextEditingController weightController = TextEditingController();
|
||||
TextEditingController countController = TextEditingController();
|
||||
TextEditingController lossController = TextEditingController();
|
||||
TextEditingController approvedWithOtpController = TextEditingController();
|
||||
|
||||
RxBool approvedWithOtpCode = false.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
getkillHouseBars();
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
debounce(
|
||||
searchedValue,
|
||||
(callback) => getkillHouseBars(),
|
||||
time: Duration(milliseconds: 2000),
|
||||
);
|
||||
super.onReady();
|
||||
ever(approvedWithOtpCode, (callback) {
|
||||
if (callback == false) {
|
||||
approvedWithOtpController.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> getkillHouseBars([bool isLoadingMore = false]) async {
|
||||
if (isLoadingMore) {
|
||||
isLoadingMoreAllocationsMade.value = true;
|
||||
} else {
|
||||
enteredBars.value =
|
||||
Resource<PaginationModel<KillHouseBarsResponse>>.loading();
|
||||
}
|
||||
|
||||
if (searchedValue.value != null &&
|
||||
searchedValue.value!.trim().isNotEmpty &&
|
||||
currentPage.value > 1) {
|
||||
currentPage.value = 1;
|
||||
}
|
||||
|
||||
safeCall(
|
||||
call: () async => await rootLogic.killHouseRepository.getBarsForKillHouse(
|
||||
token: rootLogic.tokenService.accessToken.value!,
|
||||
queryParameters: buildQueryParams(
|
||||
queryParams: {'type': 'entered'},
|
||||
pageSize: 20,
|
||||
page: currentPage.value,
|
||||
search: 'filter',
|
||||
role: 'KillHouse',
|
||||
value: searchedValue.value,
|
||||
|
||||
),
|
||||
),
|
||||
|
||||
onSuccess: (res) async {
|
||||
await Future.delayed(Duration(milliseconds: 200));
|
||||
|
||||
if ((res?.count ?? 0) == 0) {
|
||||
enteredBars.value =
|
||||
Resource<PaginationModel<KillHouseBarsResponse>>.empty();
|
||||
} else {
|
||||
enteredBars.value =
|
||||
Resource<PaginationModel<KillHouseBarsResponse>>.success(
|
||||
PaginationModel<KillHouseBarsResponse>(
|
||||
count: res?.count ?? 0,
|
||||
next: res?.next,
|
||||
previous: res?.previous,
|
||||
results: [
|
||||
...(enteredBars.value.data?.results ?? []),
|
||||
...(res?.results ?? []),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
enteredBars.value =
|
||||
Resource<PaginationModel<KillHouseBarsResponse>>.empty();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
// TODO: Fix - chickenRepository doesn't exist in rootLogic
|
||||
// call: () async => await rootLogic.chickenRepository.setSateForArrivals(
|
||||
// token: rootLogic.tokenService.accessToken.value!,
|
||||
// request: request,
|
||||
// ),
|
||||
call: () async {},
|
||||
onSuccess: (result) {
|
||||
getkillHouseBars();
|
||||
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(
|
||||
// TODO: Fix - chickenRepository doesn't exist in rootLogic
|
||||
// call: () async => await rootLogic.chickenRepository.setSateForArrivals(
|
||||
// token: rootLogic.tokenService.accessToken.value!,
|
||||
// request: request,
|
||||
// ),
|
||||
call: () async {},
|
||||
onError: (error, stackTrace) {
|
||||
eLog(error);
|
||||
},
|
||||
onSuccess: (result) {
|
||||
getkillHouseBars();
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.dart';
|
||||
import 'package:rasadyar_chicken/data/models/response/waiting_arrival/waiting_arrival.dart';
|
||||
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
import 'logic.dart';
|
||||
|
||||
class WarehouseAndDistributionBuyInProvinceEnteredPage
|
||||
extends GetView<WarehouseAndDistributionBuyInProvinceEnteredLogic> {
|
||||
const WarehouseAndDistributionBuyInProvinceEnteredPage({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('pending'),
|
||||
labelIcon: controller.getVecPathItem('pending'),
|
||||
labelIconColor: controller.getLabelColor('pending'),
|
||||
);
|
||||
}, controller.isExpandedListIndex);
|
||||
},
|
||||
itemCount: data.value.data?.results?.length ?? 0,
|
||||
separatorBuilder: (context, index) => SizedBox(height: 8.h),
|
||||
onLoadMore: () async => controller.getkillHouseBars(true),
|
||||
);
|
||||
}, controller.enteredBars),
|
||||
);
|
||||
}
|
||||
|
||||
Row itemListWidget(KillHouseBarsResponse 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,
|
||||
visible: 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(KillHouseBarsResponse 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('pending')).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: (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',
|
||||
visible: true,
|
||||
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.getkillHouseBars(),
|
||||
); */
|
||||
},
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.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/features/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<KillHouseBarsResponse>>> waitingBars =
|
||||
Resource<PaginationModel<KillHouseBarsResponse>>.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) => getKillHouseBars(),
|
||||
time: Duration(milliseconds: timeDebounce),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
super.onReady();
|
||||
getKillHouseBars();
|
||||
approvedWithOtpController.addListener(() {
|
||||
isButtonConfirm.value = approvedWithOtpController.text.trim().length > 4;
|
||||
});
|
||||
}
|
||||
|
||||
void setSearchValue(String? data) {
|
||||
searchedValue.value = data?.trim();
|
||||
}
|
||||
|
||||
Future<void> getKillHouseBars([bool isLoadingMore = false]) async {
|
||||
if (isLoadingMore) {
|
||||
isLoadingMoreAllocationsMade.value = true;
|
||||
} else {
|
||||
waitingBars.value =
|
||||
Resource<PaginationModel<KillHouseBarsResponse>>.loading();
|
||||
}
|
||||
|
||||
if (searchedValue.value != null &&
|
||||
searchedValue.value!.trim().isNotEmpty &&
|
||||
currentPage.value > 1) {
|
||||
currentPage.value = 1;
|
||||
}
|
||||
|
||||
safeCall(
|
||||
call: () async => await rootLogic.killHouseRepository.getBarsForKillHouse(
|
||||
token: rootLogic.tokenService.accessToken.value!,
|
||||
queryParameters: buildQueryParams(
|
||||
queryParams: {'type': 'notentered'},
|
||||
pageSize: 20,
|
||||
page: currentPage.value,
|
||||
search: 'filter',
|
||||
role: 'KillHouse',
|
||||
value: searchedValue.value,
|
||||
|
||||
),
|
||||
),
|
||||
onSuccess: (res) async {
|
||||
await Future.delayed(Duration(milliseconds: 200));
|
||||
|
||||
if ((res?.count ?? 0) == 0) {
|
||||
waitingBars.value =
|
||||
Resource<PaginationModel<KillHouseBarsResponse>>.empty();
|
||||
} else {
|
||||
waitingBars.value =
|
||||
Resource<PaginationModel<KillHouseBarsResponse>>.success(
|
||||
PaginationModel<KillHouseBarsResponse>(
|
||||
count: res?.count ?? 0,
|
||||
next: res?.next,
|
||||
previous: res?.previous,
|
||||
results: [
|
||||
...(waitingBars.value.data?.results ?? []),
|
||||
...(res?.results ?? []),
|
||||
],
|
||||
),
|
||||
);
|
||||
flashingFabBgColor();
|
||||
}
|
||||
waitingBars.value =
|
||||
Resource<PaginationModel<KillHouseBarsResponse>>.empty();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// TODO: Fix - chickenRepository doesn't exist in rootLogic
|
||||
safeCall(
|
||||
showError: true,
|
||||
showSuccess: true,
|
||||
// call: () async => await rootLogic.chickenRepository.setSateForArrivals(
|
||||
// token: rootLogic.tokenService.accessToken.value!,
|
||||
// request: request,
|
||||
// ),
|
||||
call: () async {},
|
||||
onError: (error, stackTrace) {
|
||||
eLog(error);
|
||||
},
|
||||
onSuccess: (result) {
|
||||
getKillHouseBars();
|
||||
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);
|
||||
|
||||
// TODO: Fix - chickenRepository doesn't exist in rootLogic
|
||||
safeCall(
|
||||
// call: () async => await rootLogic.chickenRepository.setSateForArrivals(
|
||||
// token: rootLogic.tokenService.accessToken.value!,
|
||||
// request: request,
|
||||
// ),
|
||||
call: () async {},
|
||||
onError: (error, stackTrace) {
|
||||
eLog(error);
|
||||
},
|
||||
onSuccess: (result) {
|
||||
getKillHouseBars();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,426 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.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.getKillHouseBars(true),
|
||||
);
|
||||
}, controller.waitingBars),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Row itemListWidget(KillHouseBarsResponse 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} ',
|
||||
'asdasd',
|
||||
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: 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('asdasd'),
|
||||
/* Text(
|
||||
(item.approvedPriceStatus ?? false) ? 'دولتی' : 'آزاد',
|
||||
style: AppFonts.yekan12Bold.copyWith(
|
||||
color: (item.approvedPriceStatus ?? false)
|
||||
? AppColor.blueNormal
|
||||
: AppColor.greenNormal,
|
||||
),
|
||||
), */
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Container itemListExpandedWidget(KillHouseBarsResponse 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} ',
|
||||
' sasssss ',
|
||||
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 ?? 'ندارد'}',
|
||||
'swwwqqqqqqqqqqq',
|
||||
style: AppFonts.yekan14.copyWith(
|
||||
color: AppColor.blueNormal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
Text(
|
||||
//'${item.date?.toJalali.formatter.y}',
|
||||
'1404',
|
||||
style: AppFonts.yekan20.copyWith(color: AppColor.textColor),
|
||||
),
|
||||
|
||||
Text(
|
||||
//'${item.date?.toJalali.formatter.tHH}:${item.date?.toJalali.formatter.tMM ?? 'ندارد'}',
|
||||
'12:00',
|
||||
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
buildRow(
|
||||
title: 'مشخصات فروشنده',
|
||||
value:
|
||||
//'${controller.rootLogic.isKillHouse(item) ? item.killHouse?.killHouseOperator?.user?.fullname : item.steward?.user?.fullname} ',
|
||||
'sasdasd',
|
||||
),
|
||||
buildRow(
|
||||
title: 'تلفن فروشنده',
|
||||
value:
|
||||
//'${controller.rootLogic.isKillHouse(item) ? item.killHouse?.killHouseOperator?.user?.mobile : item.steward?.user?.mobile} ',
|
||||
'09123456789',
|
||||
valueStyle: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
|
||||
),
|
||||
buildRow(
|
||||
title: 'نوع تخصیص',
|
||||
value: 'item.allocationType?.faAllocationType '?? 'ندارد',
|
||||
),
|
||||
buildRow(title: ' سهمیه', value: 'item.quota?.faTitle '?? 'ندارد'),
|
||||
buildRow(
|
||||
title: 'نوع فروش',
|
||||
value: 'asdasd',
|
||||
),
|
||||
buildRow(title: 'محصول', value: 'item.product?.name '?? 'ندارد'),
|
||||
buildRow(
|
||||
title: 'تاریخ تولید گوشت',
|
||||
value: 'item.productionDate?.toJalali.toJalaliDateTime() '?? 'ندارد',
|
||||
),
|
||||
buildRow(
|
||||
title: 'وزن خریداری شده',
|
||||
value: 'item.weightOfCarcasses?.separatedByCommaFa '?? 'ندارد',
|
||||
),
|
||||
buildRow(
|
||||
title: 'قیمت هر کیلوگرم',
|
||||
titleLabel: (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.getKillHouseBars(),
|
||||
); */
|
||||
},
|
||||
borderColor: AppColor.redNormal,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget conformationBottomSheet(KillHouseBarsResponse item) {
|
||||
//todo
|
||||
//controller.weightController.text = item.weightOfCarcasses.separatedByComma;
|
||||
controller.weightController.text = 352301.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),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,328 @@
|
||||
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/features/kill_house/warehouse_and_distribution/buy/logic.dart';
|
||||
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/root/logic.dart';
|
||||
import 'package:rasadyar_chicken/features/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());
|
||||
|
||||
// TODO: Fix - rolesProductsModel doesn't exist, use rolesProduct instead
|
||||
// selectedProduct.value = rootLogic.rolesProductsModel.first;
|
||||
selectedProduct.value = rootLogic.rolesProduct.value;
|
||||
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
|
||||
}
|
||||
// TODO: Fix - chickenRepository doesn't exist in rootLogic, need to use killHouseRepository or inject chickenRepository
|
||||
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(),
|
||||
// ),
|
||||
// ),
|
||||
call: () async => null as PaginationModel<StewardFreeBar>?,
|
||||
onSuccess: (res) async {
|
||||
await Future.delayed(Duration(milliseconds: 500));
|
||||
// TODO: Fix - res type issues
|
||||
// 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 ?? []),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
purchaseOutOfProvinceList.value =
|
||||
Resource<PaginationModel<StewardFreeBar>>.empty();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> getCites() async {
|
||||
// TODO: Fix - chickenRepository doesn't exist in rootLogic
|
||||
await safeCall(
|
||||
// call: () =>
|
||||
// rootLogic.chickenRepository.getCity(provinceName: selectedProvince.value?.name ?? ''),
|
||||
call: () async => null as List<IranProvinceCityModel>?,
|
||||
onSuccess: (result) {
|
||||
// TODO: Fix - result type issues
|
||||
// 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 {
|
||||
// TODO: Fix - chickenRepository doesn't exist in rootLogic
|
||||
// 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);
|
||||
// TODO: Fix - rolesProductsModel doesn't exist, use rolesProduct instead
|
||||
// selectedProduct.value = rootLogic.rolesProductsModel.firstWhere(
|
||||
// (element) => element.key == item.product!.key,
|
||||
// );
|
||||
if (rootLogic.rolesProduct.value?.key == item.product!.key) {
|
||||
selectedProduct.value = rootLogic.rolesProduct.value;
|
||||
}
|
||||
|
||||
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,
|
||||
// TODO: Fix - chickenRepository doesn't exist in rootLogic
|
||||
// call: () => rootLogic.chickenRepository.editStewardPurchasesOutSideOfTheProvince(
|
||||
// token: rootLogic.tokenService.accessToken.value!,
|
||||
// body: edit,
|
||||
// ),
|
||||
call: () async {},
|
||||
onSuccess: (result) {
|
||||
onRefresh();
|
||||
rootLogic.onRefresh();
|
||||
toggleExpansion();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> deleteStewardPurchaseOutOfProvince(String key) async {
|
||||
await safeCall(
|
||||
// TODO: Fix - chickenRepository doesn't exist in rootLogic
|
||||
// call: () => rootLogic.chickenRepository.deleteStewardPurchasesOutSideOfTheProvince(
|
||||
// token: rootLogic.tokenService.accessToken.value!,
|
||||
// queryParameters: buildRawQueryParams(queryParams: {'key': key}),
|
||||
// ),
|
||||
call: () async {},
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
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/features/kill_house/root/logic.dart';
|
||||
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/root/logic.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
class WarehouseAndDistributionHomeLogic extends GetxController {
|
||||
WarehouseAndDistributionRootLogic rootLogic =
|
||||
Get.find<WarehouseAndDistributionRootLogic>();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
Future<void> refreshData() async {
|
||||
await Future.wait([
|
||||
rootLogic.getRolesProducts(),
|
||||
rootLogic.getInfoSaleDashboard(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,249 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.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/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/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/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/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/features/common/profile/view.dart';
|
||||
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/buy/view.dart';
|
||||
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/home/view.dart';
|
||||
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/sale/view.dart';
|
||||
import 'package:rasadyar_chicken/features/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;
|
||||
|
||||
late DioRemote dioRemote;
|
||||
var tokenService = Get.find<TokenStorageService>();
|
||||
|
||||
RxInt currentPage = 2.obs;
|
||||
List<Widget> pages = [
|
||||
WarehouseAndDistributionBuyPage(),
|
||||
WarehouseAndDistributionSalePage(),
|
||||
WarehouseAndDistributionHomePage(),
|
||||
WarehouseAndDistributionSegmentationPage(),
|
||||
ProfilePage(),
|
||||
];
|
||||
|
||||
late KillHouseRepository killHouseRepository;
|
||||
late ChickenRepository chickenRepository;
|
||||
|
||||
final defaultRoutes = <int, String>{
|
||||
0: ChickenRoutes.buyWarehouseAndDistribution,
|
||||
1: ChickenRoutes.saleWarehouseAndDistribution,
|
||||
};
|
||||
|
||||
Rxn<ProductModel> rolesProduct = Rxn<ProductModel>();
|
||||
Rxn<WidelyUsedLocalModel> widelyUsedList = Rxn<WidelyUsedLocalModel>();
|
||||
|
||||
Rxn<BroadcastPrice> broadcastPrice = Rxn<BroadcastPrice>();
|
||||
Rxn<KillHouseSalesInfoDashboard> salesInfoDashboard =
|
||||
Rxn<KillHouseSalesInfoDashboard>();
|
||||
Rxn<StewardRemainWeight> remainWeight = Rxn<StewardRemainWeight>();
|
||||
|
||||
RxList<ErrorLocationType> errorLocationType = RxList();
|
||||
RxMap<int, dynamic> inventoryExpandedList = RxMap();
|
||||
Rxn<ProductModel> inventoryModel = Rxn<ProductModel>();
|
||||
RxList<IranProvinceCityModel> provinces = <IranProvinceCityModel>[].obs;
|
||||
|
||||
// Cancel tokens for API calls
|
||||
CancelToken? _inventoryCancelToken;
|
||||
CancelToken? _provincesCancelToken;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
|
||||
killHouseRepository = diChicken.get<KillHouseRepository>();
|
||||
chickenRepository = diChicken.get<ChickenRepository>();
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
super.onReady();
|
||||
|
||||
if (provinces.isEmpty) {
|
||||
getProvinces();
|
||||
}
|
||||
if (salesInfoDashboard.value == null) {
|
||||
getInfoSaleDashboard();
|
||||
}
|
||||
if (rolesProduct.value == null) {
|
||||
getRolesProducts();
|
||||
}
|
||||
if (broadcastPrice.value == null) {
|
||||
getBroadcastPrice();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
// Cancel any ongoing requests when controller is disposed
|
||||
_inventoryCancelToken?.cancel();
|
||||
_provincesCancelToken?.cancel();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
Future<void> onRefresh() async {
|
||||
await Future.wait([
|
||||
getInfoSaleDashboard(),
|
||||
getRolesProducts(),
|
||||
getProvinces(),
|
||||
getBroadcastPrice(),
|
||||
]);
|
||||
}
|
||||
|
||||
void toggleExpanded(int index) {
|
||||
if (inventoryExpandedList.keys.contains(index)) {
|
||||
inventoryExpandedList.remove(index);
|
||||
} else {
|
||||
inventoryExpandedList[index] = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getInfoSaleDashboard() async {
|
||||
// Cancel previous request if still running
|
||||
_inventoryCancelToken?.cancel();
|
||||
_inventoryCancelToken = CancelToken();
|
||||
|
||||
await safeCall<KillHouseSalesInfoDashboard?>(
|
||||
call: () async => await killHouseRepository.getInfoDashboard(
|
||||
token: tokenService.accessToken.value!,
|
||||
),
|
||||
onSuccess: (result) {
|
||||
if (result != null) {
|
||||
salesInfoDashboard.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> getBroadcastPrice() async {
|
||||
safeCall(
|
||||
call: () async => await chickenRepository.getBroadcastPrice(
|
||||
token: tokenService.accessToken.value!,
|
||||
),
|
||||
onSuccess: (result) {
|
||||
broadcastPrice.value = result;
|
||||
},
|
||||
onError: (error, stacktrace) {},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> getRolesProducts() async {
|
||||
await safeCall(
|
||||
call: () async => await chickenRepository.getRolesProducts(
|
||||
token: tokenService.accessToken.value!,
|
||||
queryParameters: buildRawQueryParams(role: 'KillHouse'),
|
||||
),
|
||||
onSuccess: (result) {
|
||||
if (result != null) {
|
||||
rolesProduct.value = result.first;
|
||||
}
|
||||
},
|
||||
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";
|
||||
}
|
||||
@@ -0,0 +1,565 @@
|
||||
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/features/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),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
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/features/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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,507 @@
|
||||
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/features/kill_house/warehouse_and_distribution/root/logic.dart';
|
||||
import 'package:rasadyar_chicken/features/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!,
|
||||
role: 'Steward',
|
||||
),
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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/features/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),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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/features/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();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -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/features/kill_house/warehouse_and_distribution/root/logic.dart';
|
||||
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/sale/logic.dart';
|
||||
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/sales_out_of_province_buyers/logic.dart';
|
||||
import 'package:rasadyar_chicken/features/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("تاریخ تولید نمی تواند قبل از تاریخ فروش باشد"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,233 @@
|
||||
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/features/kill_house/warehouse_and_distribution/root/logic.dart';
|
||||
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/sale/logic.dart';
|
||||
import 'package:rasadyar_chicken/features/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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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(),
|
||||
);
|
||||
}
|
||||
@@ -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/features/kill_house/warehouse_and_distribution/root/logic.dart';
|
||||
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/sale/logic.dart';
|
||||
import 'package:rasadyar_chicken/features/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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
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/features/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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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/features/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,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,396 @@
|
||||
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/features/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),
|
||||
],
|
||||
),
|
||||
);
|
||||
}); */
|
||||
return Container();
|
||||
}
|
||||
|
||||
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;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -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_entered/logic.dart';
|
||||
export 'buy_in_province_entered/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';
|
||||
Reference in New Issue
Block a user