feat: add otp code for sell order

fix: form for segmentation
This commit is contained in:
2025-11-04 15:48:48 +03:30
parent 6269445536
commit f2183fd2de
22 changed files with 1220 additions and 1288 deletions

View File

@@ -5,7 +5,6 @@ import 'package:rasadyar_chicken/data/models/response/kill_house_distribution_in
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_chicken/presentation/widget/steward/widely_used/view.dart';
import 'package:rasadyar_core/core.dart';
import 'package:rasadyar_core/presentation/widget/error_widget.dart';
import 'logic.dart';
@@ -441,7 +440,6 @@ class HomePage extends GetView<HomeLogic> {
isLoading: data.value == null,
description: data.value?.totalGovernmentalRemainWeight?.separatedByCommaFa ?? '0',
iconPath: Assets.vec.cubeCardGovermentSvg.path,
iconColor: AppColor.textColor,
bgDescriptionColor: const Color(0xFFF5ECEE),
bgLabelColor: const Color(0xFFDEC1C7),

View File

@@ -60,6 +60,7 @@ class SalesInProvinceLogic extends GetxController {
SubmitStewardAllocation? tmpStewardAllocation;
Rxn<Jalali> productionDate = Rxn(null);
Rxn<int> remainingStock = Rxn(null);
Map<String, DayData> freeProductionDateData = {};
Map<String, DayData> governmentalProductionDateData = {};
@@ -76,6 +77,11 @@ class SalesInProvinceLogic extends GetxController {
getGuilds();
});
ever(quotaType, (_) {
remainingStock.value = null;
productionDate.value = null;
});
debounce(weight, time: Duration(milliseconds: 110), (callback) {
totalCost.value = callback * pricePerKilo.value;
});
@@ -275,7 +281,8 @@ class SalesInProvinceLogic extends GetxController {
call: () async => await rootLogic.chickenRepository.getGuilds(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildQueryParams(
queryParams: {'free': saleType.value == 2 ? true : false},
//queryParams: {'free': saleType.value == 2 ? true : false},
queryParams: {'all': true},
role: 'Steward',
),
),

View File

@@ -1,8 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.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/presentation/pages/steward/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';
@@ -78,7 +76,7 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
RFab.add(
onPressed: () {
Get.bottomSheet(
addOrEditBottomSheet(),
addOrEditBottomSheet(controller),
isScrollControlled: true,
backgroundColor: Colors.transparent,
).whenComplete(() {
@@ -367,7 +365,7 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
onPressed: () {
controller.setEditData(item);
Get.bottomSheet(
addOrEditBottomSheet(true),
addOrEditBottomSheet(controller, isEditMode: true),
isScrollControlled: true,
backgroundColor: Colors.transparent,
).whenComplete(() {
@@ -402,472 +400,6 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
);
}
Widget addOrEditBottomSheet([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(),
const SizedBox(height: 12),
Visibility(
visible: isEditMode == false,
child: 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(
groupValue: controller.saleType.value,
onChanged: (value) {
controller.saleType.value = value!;
controller.selectedGuildModel.value = null;
controller.selectedGuildModel.refresh();
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Row(
children: [
Radio(value: 1),
Text('فروش اختصاصی', style: AppFonts.yekan14),
],
),
),
Expanded(
child: Row(
children: [
Radio(value: 2),
Text('فروش آزاد', style: AppFonts.yekan14),
],
),
),
],
),
);
}, controller.saleType),
),
const SizedBox(height: 12),
guildsDropDown(),
],
),
),
),
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 ?? Jalali.now()).formatCompactDate(),
);
}, controller.fromDateFilter),
RTextField(
controller: controller.weightController,
keyboardType: TextInputType.number,
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
SeparatorInputFormatter(),
],
validator: (value) {
if (int.parse(value!.clearComma) >
(controller.rootLogic.inventoryModel.value?.totalRemainWeight?.toInt() ??
100)) {
return 'وزن تخصیصی بیشتر از موجودی انبار است';
}
return null;
},
onChanged: (p0) {
controller.weight.value = int.tryParse(p0.clearComma) ?? 0;
},
label: 'وزن لاشه (کیلوگرم)',
),
Visibility(
visible: isEditMode == false,
child: Column(
children: [
SizedBox(height: 12),
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
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalGovernmentalRemainWeight ??
-1) >
0
? () {
controller.quotaType.value = 1;
}
: null,
child: Row(
children: [
Radio(
value: 1,
enabled:
(controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalGovernmentalRemainWeight ??
-1) >
0,
),
Text(
'انبار دولتی',
style: AppFonts.yekan14.copyWith(
color:
((controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalGovernmentalRemainWeight ??
-1) >
0)
? AppColor.textColor
: AppColor.labelTextColor,
),
),
],
),
),
),
Expanded(
child: GestureDetector(
onTap:
(controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalFreeRemainWeight ??
-1) >
0
? () {
controller.quotaType.value = 2;
}
: null,
child: Row(
children: [
Radio(
value: 2,
enabled:
(controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalFreeRemainWeight ??
-1) >
0,
),
Text(
'انبار آزاد',
style: AppFonts.yekan14.copyWith(
color:
((controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalFreeRemainWeight ??
-1) >
0)
? AppColor.textColor
: AppColor.labelTextColor,
),
),
],
),
),
),
],
),
);
}),
],
),
),
SizedBox(height: 12),
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),
],
),
),
),
],
),
);
}),
],
),
),
],
),
),
Obx(() {
return MonthlyDataCalendar(
label: 'تاریخ تولید گوشت',
selectedDate: controller.productionDate.value?.formatCompactDate(),
onDateSelect: (value) {
controller.productionDate.value = value.date;
},
dayData: controller.quotaType.value == 1
? controller.governmentalProductionDateData
: controller.freeProductionDateData,
);
}),
RTextField(
variant: RTextFieldVariant.noBorder,
controller: controller.pricePerKiloController,
borderColor: AppColor.darkGreyLight,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
SeparatorInputFormatter(),
],
filledColor: AppColor.bgLight,
filled: true,
enabled:
(controller.priceType.value == 2 ||
(controller.selectedProductModel.value?.approvedPriceStatus == false)),
onChanged: (p0) {
controller.pricePerKilo.value = int.tryParse(p0.clearComma) ?? 0;
},
keyboardType: TextInputType.number,
label: 'قیمت هر کیلو (ريال)',
),
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();
}
: () async {
await controller.submitAllocation();
},
);
}, controller.isValid),
const SizedBox(height: 20),
],
),
),
);
}
Widget guildsDropDown() {
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})'
: 'انتخاب مباشر/صنف',
),
);
});
}
Widget productDropDown() {
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(),
Text(
'موجودی:${controller.rootLogic.inventoryModel.value?.totalRemainWeight.separatedByCommaFa ?? 0}',
),
],
),
);
});
}
Widget filterBottomSheet() {
return BaseBottomSheet(
height: 200,

View File

@@ -0,0 +1,342 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rasadyar_chicken/data/models/response/guild/guild_model.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/presentation/pages/steward/sales_in_province/logic.dart';
import 'package:rasadyar_core/core.dart';
Widget addOrEditBottomSheet(SalesInProvinceLogic 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),
RTextField(
controller: TextEditingController(),
filledColor: AppColor.bgLight,
label: 'تاریخ',
readonly: true,
borderColor: AppColor.darkGreyLight,
initText: Jalali.now().formatCompactDate(),
),
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();
}
: () async {
await controller.submitAllocation();
},
);
}, controller.isValid),
const SizedBox(height: 20),
],
),
),
);
}
Widget guildsDropDown(SalesInProvinceLogic 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})'
: 'انتخاب مباشر/صنف',
),
);
});
}
Widget productDropDown(SalesInProvinceLogic 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),
],
),
);
});
}

View File

@@ -37,8 +37,15 @@ class SalesOutOfProvinceLogic extends GetxController {
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;
@@ -49,6 +56,7 @@ class SalesOutOfProvinceLogic extends GetxController {
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 = {};
@@ -77,6 +85,17 @@ class SalesOutOfProvinceLogic extends GetxController {
_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() {
@@ -153,7 +172,7 @@ class SalesOutOfProvinceLogic extends GetxController {
quarantineCodeController.addListener(checkSalesFormValid);
saleWeightController.addListener(() {
checkSalesFormValid();
var weight = int.parse(saleWeightController.text.clearComma);
weight.value = int.parse(saleWeightController.text.clearComma);
var res = (weight / selectedProduct.value!.weightAverage!.toInt()).round();
saleCountController.text = res.separatedByComma;
});
@@ -185,6 +204,8 @@ class SalesOutOfProvinceLogic extends GetxController {
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 {
@@ -268,6 +289,40 @@ class SalesOutOfProvinceLogic extends GetxController {
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;

View File

@@ -94,27 +94,6 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
);
}
/* Padding segmentWidget() {
return Padding(
padding: const EdgeInsets.fromLTRB(8, 0, 8, 8),
child: Row(
children: [
Expanded(
child: RSegment(
children: ['فروش', 'خریداران'],
selectedIndex: controller.selectedSegmentIndex.value,
borderColor: const Color(0xFFB4B4B4),
selectedBorderColor: AppColor.blueNormal,
selectedBackgroundColor: AppColor.blueLight,
onSegmentSelected: (index) => controller.selectedSegmentIndex.value = index,
backgroundColor: AppColor.whiteGreyNormal,
),
),
],
),
);
}*/
Widget filterBottomSheet() => filterBottomSheetWidget(
fromDate: controller.fromDateFilter,
onChangedFromDate: (jalali) => controller.fromDateFilter.value = jalali,
@@ -277,6 +256,32 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
valueLabel: 'قطعه',
),
item.registerCode == null
? Row(
children: [
Text(
'کد احراز',
style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDarkHover),
),
Spacer(),
RElevated(
width: 95.w,
height: 20.h,
textStyle: AppFonts.yekan12,
backgroundColor: AppColor.blueDarkHover,
text: 'ارسال کد',
onPressed: () {
Get.bottomSheet(bottomSendOtpSheetSellCode(item)).then((value) {
controller.otpCode.value = '';
controller.otpCodeSell.clear();
});
},
),
],
)
: buildRow(title: 'کد احراز ', value: '${item.registerCode}'),
buildRow(title: 'کد قرنطینه ', value: item.clearanceCode ?? 'بدون کد'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 16.w,
@@ -347,272 +352,102 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
child: Column(
spacing: 12,
children: [
ObxValue((data) {
return RTextField(
controller: TextEditingController(),
filledColor: AppColor.bgLight,
filled: true,
label: 'تاریخ',
onTap: () {
Get.bottomSheet(
modalDatePicker((value) {
controller.saleDate.value = value;
controller.saleDate.refresh();
}),
);
},
borderColor: AppColor.darkGreyLight,
initText: data.value.formatCompactDate(),
);
}, controller.saleDate),
Visibility(visible: isOnEdit == false, child: _buyerWidget()),
RTextField(
controller: controller.quarantineCodeController,
label: 'کد قرنطینه',
borderColor: AppColor.darkGreyLight,
controller: TextEditingController(),
filledColor: AppColor.bgLight,
filled: true,
validator: (value) {
if (value == null) {
return 'لطفاً کد قرنطینه را وارد کنید';
}
return null;
},
label: 'تاریخ',
readonly: true,
borderColor: AppColor.darkGreyLight,
initText: Jalali.now().formatCompactDate(),
),
Visibility(
visible: isOnEdit == false,
child: Column(
spacing: 12,
children: [
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: 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,
),
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
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalGovernmentalRemainWeight ??
-1) >
0
? () {
controller.quotaType.value = 1;
}
: null,
child: Row(
children: [
Radio(
value: 1,
enabled:
(controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalGovernmentalRemainWeight ??
-1) >
0,
),
Text(
'انبار دولتی',
style: AppFonts.yekan14.copyWith(
color:
((controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalGovernmentalRemainWeight ??
-1) >
0)
? AppColor.textColor
: AppColor.labelTextColor,
),
),
],
),
),
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
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalFreeRemainWeight ??
-1) >
0
? () {
controller.quotaType.value = 2;
}
: null,
child: Row(
children: [
Radio(
value: 2,
enabled:
(controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalFreeRemainWeight ??
-1) >
0,
),
Text(
'انبار آزاد',
style: AppFonts.yekan14.copyWith(
color:
((controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalFreeRemainWeight ??
-1) >
0)
? AppColor.textColor
: AppColor.labelTextColor,
),
),
],
),
),
),
],
),
),
);
}),
],
),
),
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.saleType.value,
onChanged: (value) {
controller.saleType.value = value ?? 0;
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: GestureDetector(
onTap:
(controller.broadcastPrice.value?.active ?? false)
? () {
controller.saleType.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.quotaType.value = 2;
},
child: Row(
children: [
Radio(value: 2),
Text('آزاد', style: AppFonts.yekan14),
],
),
Expanded(
child: GestureDetector(
onTap: () {
controller.saleType.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;
},
dayData: controller.quotaType.value == 1
? controller.governmentalProductionDateData
: controller.freeProductionDateData,
);
}),
],
],
),
);
}),
],
),
),
),
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: isOnEdit == false, child: _buyerWidget()),
RTextField(
controller: controller.saleWeightController,
label: 'وزن لاشه (کیلوگرم)',
keyboardType: TextInputType.number,
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
autoValidateMode: AutovalidateMode.onUserInteraction,
filled: true,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
@@ -620,8 +455,9 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
],
validator: (value) {
if (value == null) {
return 'لطفاً وزن لاشه را وارد کنید';
if ((int.tryParse(value?.clearComma ?? '0') ?? 0) >
(controller.remainingStock.value ?? 0)) {
return 'وزن تخصیصی بیشتر از موجودی انبار است';
}
return null;
},
@@ -641,9 +477,137 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
SeparatorInputFormatter(),
],
validator: (value) {
if ((int.tryParse(value?.clearComma ?? '0') ?? 0) >
(controller.remainingStock.value ?? 0)) {
return 'وزن تخصیصی بیشتر از موجودی انبار است';
}
return null;
},
),
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.saleType.value,
onChanged: (value) {
controller.saleType.value = 2;
},
child: Row(
children: [
Expanded(
child: GestureDetector(
onTap: (controller.broadcastPrice.value?.active ?? false)
? () {
controller.saleType.value = 2;
}
: 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.saleType.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.saleType),
RTextField(
variant: RTextFieldVariant.noBorder,
enabled: false,
keyboardType: TextInputType.number,
filledColor: AppColor.bgLight,
filled: true,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
SeparatorInputFormatter(),
],
controller: controller.totalCostController,
label: 'هزینه کل (ريال)',
),
RTextField(
controller: controller.quarantineCodeController,
label: 'کد قرنطینه',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
validator: (value) {
if (value == null) {
return 'لطفاً قطعه لاشه را وارد کنید';
return 'لطفاً کد قرنطینه را وارد کنید';
}
return null;
},
@@ -713,9 +677,9 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
Text(item?.name ?? 'انتخاب محصول'),
Spacer(),
Text(
'موجودی:${controller.rootLogic.inventoryModel.value?.totalRemainWeight.separatedByCommaFa ?? 0}',
),
ObxValue((data) {
return Visibility(visible: data.value != null, child: Text('موجودی: $data'));
}, controller.remainingStock),
],
),
);
@@ -913,4 +877,29 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
),
);
}
Widget bottomSendOtpSheetSellCode(StewardFreeSaleBar item) {
return BaseBottomSheet(
height: 190.h,
child: Column(
children: [
SizedBox(height: 12),
RTextField(
controller: controller.otpCodeSell,
onChanged: (data) => controller.otpCode.value = data,
label: 'کد احراز',
),
SizedBox(height: 12),
RElevated(
onPressed: () {
controller.sendSaleOtpCode(item);
},
isFullWidth: true,
text: "ارسال کد",
),
SizedBox(height: 12),
],
),
);
}
}

View File

@@ -78,7 +78,7 @@ class SalesOutOfProvinceSalesListPage extends GetView<SalesOutOfProvinceSalesLis
Expanded(
flex: 3,
child: Text(
item.date?.formattedJalaliDate ?? 'N/A',
item.date?.formattedJalaliDate ?? 'ندارد',
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
),
@@ -90,14 +90,14 @@ class SalesOutOfProvinceSalesListPage extends GetView<SalesOutOfProvinceSalesLis
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
item.buyer?.fullname ?? 'N/A',
item.buyer?.fullname ?? 'ندارد',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
SizedBox(height: 2),
Text(
item.buyer?.mobile ?? 'N/A',
item.buyer?.mobile ?? 'ندارد',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark),
),
@@ -112,7 +112,7 @@ class SalesOutOfProvinceSalesListPage extends GetView<SalesOutOfProvinceSalesLis
spacing: 8,
children: [
Text(
item.buyer?.unitName ?? 'N/A',
item.buyer?.unitName ?? 'ندارد',
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
),
@@ -124,7 +124,6 @@ class SalesOutOfProvinceSalesListPage extends GetView<SalesOutOfProvinceSalesLis
],
),
),
],
);
}
@@ -163,12 +162,12 @@ class SalesOutOfProvinceSalesListPage extends GetView<SalesOutOfProvinceSalesLis
spacing: 3,
children: [
Text(
item.date?.toJalali.formatter.wN ?? 'N/A',
item.date?.toJalali.formatter.wN ?? 'ندارد',
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
),
Text(
'${item.date?.toJalali.formatter.d} ${item.date?.toJalali.formatter.mN ?? 'N/A'}',
'${item.date?.toJalali.formatter.d} ${item.date?.toJalali.formatter.mN ?? 'ندارد'}',
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
],
@@ -180,15 +179,15 @@ class SalesOutOfProvinceSalesListPage extends GetView<SalesOutOfProvinceSalesLis
),
Text(
'${item.date?.toJalali.formatter.tHH}:${item.date?.toJalali.formatter.tMM ?? 'N/A'}',
'${item.date?.toJalali.formatter.tHH}:${item.date?.toJalali.formatter.tMM ?? 'ندارد'}',
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
),
],
),
),
buildRow(title: 'مشخصات خریدار', value: item.buyer?.fullname ?? 'N/A'),
buildRow(title: 'تلفن خریدار', value: item.buyer?.mobile ?? 'N/A'),
buildRow(title: 'نام واحد', value: item.buyer?.unitName ?? 'N/A'),
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(

View File

@@ -1,5 +1,6 @@
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';
@@ -23,7 +24,7 @@ class SegmentationLogic extends GetxController {
Rx<Jalali> toDateFilter = Jalali.now().obs;
RxnString searchedValue = RxnString();
RxInt segmentType = 1.obs;
RxInt saleType = 2.obs;
RxInt priceType = 2.obs;
RxInt quotaType = 2.obs;
GlobalKey<FormState> formKey = GlobalKey<FormState>();
TextEditingController weightController = TextEditingController(text: '0');
@@ -31,14 +32,15 @@ class SegmentationLogic extends GetxController {
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;
Rxn<Jalali?> productionDate = Rxn(null);
RxInt weight = 0.obs;
Rxn<Jalali> productionDate = Rxn(null);
Rxn<int> remainingStock = Rxn(null);
Map<String, DayData> freeProductionDateData = {};
Map<String, DayData> governmentalProductionDateData = {};
@@ -50,6 +52,10 @@ class SegmentationLogic extends GetxController {
getAllSegmentation();
getGuilds();
ever(quotaType, (_) {
remainingStock.value = null;
productionDate.value = null;
});
_updateGovernmentalProductionDateData();
_updateFreeProductionDateData();
ever(rootLogic.stewardRemainWeight, (callback) {
@@ -100,7 +106,7 @@ class SegmentationLogic extends GetxController {
time: Duration(milliseconds: timeDebounce),
);
everAll([selectedSegment, quotaType, saleType], (_) {
everAll([selectedSegment, quotaType, priceType], (_) {
validateForm();
});
@@ -116,27 +122,22 @@ class SegmentationLogic extends GetxController {
weightController.text = '0';
selectedSegment.value = null;
selectedGuildModel.value = null;
productionDate.value = Jalali.now();
productionDate.value = null;
segmentType.value = 1;
saleType.value = 2;
priceType.value = 2;
quotaType.value = 1;
remainingStock.value = null;
}
void validateForm() {
var weight = int.tryParse(weightController.text.trim().clearComma);
var hasWeight = quotaType.value == 2
? ((weight ?? 0) <= (rootLogic.stewardSalesInfoDashboard.value?.totalFreeRemainWeight ?? 0))
: ((weight ?? 0) <=
(rootLogic.stewardSalesInfoDashboard.value?.totalGovernmentalRemainWeight ?? 0));
if (!hasWeight) {
defaultShowErrorMessage("میزان وزن تخیصصی شده بیشتر از وزن باقیمانده است!");
}
var weight = int.tryParse(weightController.text.trim().clearComma) ?? 0;
var hasWeight = (remainingStock.value ?? 0) > weight;
isSubmitButtonEnabled.value =
selectedProduct.value != null &&
weightController.text.isNotEmpty &&
hasWeight &&
weight! > 0 &&
productionDate.value != null &&
weight > 0 &&
(segmentType.value == 1 || (segmentType.value == 2 && selectedGuildModel.value != null));
}
@@ -229,7 +230,7 @@ class SegmentationLogic extends GetxController {
SegmentationModel segmentationModel = SegmentationModel(
productKey: selectedProduct.value?.key,
weight: int.tryParse(weightController.text.clearComma) ?? 0,
saleType: saleType.value == 1 ? 'governmental' : 'free',
saleType: priceType.value == 1 ? 'governmental' : 'free',
quota: quotaType.value == 1 ? 'governmental' : 'free',
);
if (segmentType.value == 2) {
@@ -282,10 +283,26 @@ class SegmentationLogic extends GetxController {
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;

View File

@@ -1,8 +1,6 @@
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/data/models/response/segmentation_model/segmentation_model.dart';
import 'package:rasadyar_chicken/presentation/pages/steward/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';
@@ -60,7 +58,7 @@ class SegmentationPage extends GetView<SegmentationLogic> {
child: RFab.add(
onPressed: () {
Get.bottomSheet(
addOrEditBottomSheet(),
addOrEditBottomSheet(controller),
isScrollControlled: true,
ignoreSafeArea: false,
).whenComplete(() {
@@ -252,7 +250,7 @@ class SegmentationPage extends GetView<SegmentationLogic> {
onPressed: () {
controller.setEditData(item);
Get.bottomSheet(
addOrEditBottomSheet(true),
addOrEditBottomSheet(controller, isOnEdit: true),
isScrollControlled: true,
ignoreSafeArea: false,
).whenComplete(() {
@@ -284,454 +282,4 @@ class SegmentationPage extends GetView<SegmentationLogic> {
),
);
}
Widget addOrEditBottomSheet([bool isOnEdit = false]) {
return BaseBottomSheet(
height: isOnEdit ? 350.h : 650.h,
child: SingleChildScrollView(
child: Form(
key: controller.formKey,
child: Column(
spacing: 16,
children: [
Text(
isOnEdit ? 'ویرایش قطعه‌بندی' : 'افزودن قطعه‌بندی',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
_productDropDown(),
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.saleType),
),
const SizedBox(height: 12),
ObxValue((data) {
return Visibility(visible: data.value == 2, child: guildsDropDown());
}, controller.segmentType),
],
),
),
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.saleType.value,
onChanged: (value) {
controller.saleType.value = 2 ?? 0;
controller.selectedGuildModel.value = null;
controller.selectedGuildModel.refresh();
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: GestureDetector(
onTap: () {
//controller.saleType.value = 1;
},
child: Row(
children: [
Radio(value: 1, enabled: false),
Text(
'قیمت دولتی',
style: AppFonts.yekan14.copyWith(
color: AppColor.mediumGreyDark,
),
),
],
),
),
),
Expanded(
child: GestureDetector(
onTap: () {
controller.saleType.value = 2;
},
child: Row(
children: [
Radio(value: 2),
Text('قیمت آزاد', style: AppFonts.yekan14),
],
),
),
),
],
),
);
}),
],
),
),
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
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalGovernmentalRemainWeight ??
-1) >
0
? () {
controller.quotaType.value = 1;
}
: null,
child: Row(
children: [
Radio(
value: 1,
enabled:
(controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalGovernmentalRemainWeight ??
-1) >
0,
),
Text(
'انبار دولتی',
style: AppFonts.yekan14.copyWith(
color:
((controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalGovernmentalRemainWeight ??
-1) >
0)
? AppColor.textColor
: AppColor.labelTextColor,
),
),
],
),
),
),
Expanded(
child: GestureDetector(
onTap:
(controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalFreeRemainWeight ??
-1) >
0
? () {
controller.quotaType.value = 2;
}
: null,
child: Row(
children: [
Radio(
value: 2,
enabled:
(controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalFreeRemainWeight ??
-1) >
0,
),
Text(
'انبار آزاد',
style: AppFonts.yekan14.copyWith(
color:
((controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalFreeRemainWeight ??
-1) >
0)
? AppColor.textColor
: AppColor.labelTextColor,
),
),
],
),
),
),
],
),
);
}),
],
),
),
Obx(() {
return MonthlyDataCalendar(
label: 'تاریخ تولید گوشت',
selectedDate: controller.productionDate.value?.formatCompactDate(),
onDateSelect: (value) => controller.productionDate..value = value.date,
dayData: controller.quotaType.value == 1
? controller.governmentalProductionDateData
: controller.freeProductionDateData,
);
}),
],
),
),
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: [
UnitTextField(
hint: 'وزن',
unit: 'کیلوگرم',
controller: controller.weightController,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
SeparatorInputFormatter(),
],
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.editSegment()
: await controller.createSegment();
if (res) {
Get.back();
}
}
: null,
height: 40,
);
}, controller.isSubmitButtonEnabled);
}
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 guildsDropDown() {
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(ValueChanged<Jalali> onDateSelected) {
Jalali currentDate = Jalali.now();
Jalali? tempPickedDate;
return Container(
height: 250,
color: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
child: Row(
children: [
SizedBox(width: 20),
RElevated(
height: 35,
width: 70,
textStyle: AppFonts.yekan14.copyWith(color: Colors.white),
onPressed: () {
onDateSelected(tempPickedDate ?? Jalali.now());
Get.back();
},
text: 'تایید',
),
Spacer(),
RElevated(
height: 35,
width: 70,
backgroundColor: AppColor.error,
textStyle: AppFonts.yekan14.copyWith(color: Colors.white),
onPressed: () {
onDateSelected(tempPickedDate ?? Jalali.now());
Get.back();
},
text: 'لغو',
),
SizedBox(width: 20),
],
),
),
Divider(height: 0, thickness: 1),
Expanded(
child: Container(
child: PersianCupertinoDatePicker(
initialDateTime: controller.saleDate.value,
mode: PersianCupertinoDatePickerMode.date,
maximumDate: currentDate.addDays(3),
minimumDate: currentDate
.toDateTime()
.subtract(Duration(days: 1))
.toString()
.toJalali,
maximumYear: currentDate.year,
minimumYear: currentDate.year,
onDateTimeChanged: (dateTime) {
tempPickedDate = dateTime;
},
),
),
),
],
),
);
}
}

View File

@@ -0,0 +1,395 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rasadyar_chicken/data/models/response/guild/guild_model.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/presentation/pages/steward/segmentation/logic.dart';
import 'package:rasadyar_core/core.dart';
Widget addOrEditBottomSheet(SegmentationLogic 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(SegmentationLogic 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(SegmentationLogic controller) {
return Obx(() {
return OverlayDropdownWidget<ProductModel>(
items: controller.rootLogic.rolesProductsModel,
height: 56,
hasDropIcon: false,
background: Colors.white,
onChanged: (value) {
controller.selectedProduct.value = value;
},
selectedItem: controller.selectedProduct.value,
initialValue: controller.selectedProduct.value,
itemBuilder: (item) => Text(item.name ?? 'بدون نام'),
labelBuilder: (item) => Row(
spacing: 8,
children: [
(item?.name?.contains('مرغ گرم') ?? false)
? Assets.images.chicken.image(width: 40, height: 40)
: Assets.vec.placeHolderSvg.svg(width: 40, height: 40),
Text(item?.name ?? 'انتخاب محصول'),
Spacer(),
ObxValue((data) {
return Visibility(visible: data.value != null, child: Text('موجودی: $data'));
}, controller.remainingStock),
],
),
);
});
}
Widget guildsDropDown(SegmentationLogic 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(SegmentationLogic 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;
},
),
),
),
],
),
);
}