feat : sale in province / but out of province / out of province page

This commit is contained in:
2025-06-16 10:55:33 +03:30
parent ee489ecb84
commit e54f4ec2c3
10 changed files with 1040 additions and 904 deletions

View File

@@ -0,0 +1,147 @@
import 'package:rasadyar_auth/data/utils/safe_call.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/dashboard_kill_house_free_bar/dashboard_kill_house_free_bar.dart';
import 'package:rasadyar_chicken/data/models/response/guild/guild_model.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/data/models/response/steward_free_bar_dashboard/steward_free_bar_dashboard.dart';
import 'package:rasadyar_chicken/presentation/pages/root/logic.dart';
import 'package:rasadyar_core/core.dart';
class OutOfProvinceLogic extends GetxController {
var rootLogic = Get.find<RootLogic>();
Rxn<AllocatedMadeModel> allocatedMadeModel = Rxn<AllocatedMadeModel>();
RxList<ProductModel> rolesProductsModel = RxList<ProductModel>();
RxList<GuildModel> guildsModel = <GuildModel>[].obs;
Rxn<StewardFreeBarDashboard> stewardFreeDashboard =
Rxn<StewardFreeBarDashboard>();
@override
void onInit() {
super.onInit();
getStewardDashBord();
}
Future<void> getAllocatedMade() async {
safeCall(
call: () async => await rootLogic.chickenRepository.getAllocatedMade(
token: rootLogic.tokenService.accessToken.value!,
page: 1,
),
onSuccess: (result) {
if (result != null) {
allocatedMadeModel.value = result;
}
},
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?.results?.map((e) => e.key!).toList() ??
[],
),
onSuccess: (result) {
getAllocatedMade();
},
onError: (error, stacktrace) {},
);
}
Future<void> getRolesProducts() async {
safeCall(
call: () async => await rootLogic.chickenRepository.getRolesProducts(
token: rootLogic.tokenService.accessToken.value!,
),
onSuccess: (result) {
if (result != null) {
rolesProductsModel.value = result;
}
},
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> getKillHouseDashBord() async {
safeCall(
call: () async =>
await rootLogic.chickenRepository.getDashboardKillHouseFreeBar(
token: rootLogic.tokenService.accessToken.value!,
stratDate: DateTime.now().formattedDashedGregorian,
endDate: DateTime.now().formattedDashedGregorian,
),
onSuccess: (result) {
if (result != null) {
killHouseDashboard.value = result;
}
},
onError: (error, stacktrace) {},
);
}*/
Future<void> submitAllocation() async {}
@override
void dispose() {
rootLogic.inventoryExpandedList.clear();
super.dispose();
}
}

View File

@@ -0,0 +1,769 @@
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_core/core.dart';
import 'logic.dart';
class OutOfProvincePage extends GetView<OutOfProvinceLogic> {
OutOfProvincePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColor.bgLight,
appBar: RAppBar(
title: 'رصدطیور',
iconTitle: Assets.vec.chickenSvg.path,
titleTextStyle: AppFonts.yekan16Bold.copyWith(color: Colors.white),
centerTitle: true,
hasBack: false,
leadingWidth: 130,
leading: Row(
mainAxisSize: MainAxisSize.min,
spacing: 6,
children: [
Assets.vec.cubeSearchSvg.svg(
width: 24,
height: 24,
colorFilter: const ColorFilter.mode(Colors.white, BlendMode.srcIn),
),
Text('خارج استان', style: AppFonts.yekan16Bold.copyWith(color: Colors.white)),
],
),
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
spacing: 8,
children: [
Expanded(
child: _typeOuterInfoCard(
title: 'خرید خارج استان',
iconPath: Assets.vec.cubeBottomRotationSvg.path,
foregroundColor: AppColor.blueNormal,
onTap: () {
Get.toNamed(ChickenRoutes.salesOutOfProvince,id:1);
},
),
),
Expanded(
child: _typeOuterInfoCard(
title: 'فروش خارج استان',
iconPath: Assets.vec.cubeTopRotationSvg.path,
foregroundColor: AppColor.greenDark,
onTap: () {
Get.toNamed(ChickenRoutes.buysOutOfProvince,id: 1);
},
),
),
],
),
),
/* SizedBox(height: 12),
ObxValue((model) => summaryOfInformation(model.value), controller.stewardFreeDashboard),
Expanded(
child: ListView.separated(
padding: const EdgeInsets.fromLTRB(8, 12, 8, 100),
shrinkWrap: true,
physics: BouncingScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 10),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)),
child: Column(
spacing: 8,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Assets.vec.editSvg.svg(
width: 20,
height: 20,
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
),
Text(
'لرستان - خرم آباد',
textAlign: TextAlign.center,
style: AppFonts.yekan16.copyWith(color: AppColor.greenDark),
),
Assets.vec.trashSvg.svg(
width: 20,
height: 20,
colorFilter: ColorFilter.mode(AppColor.error, BlendMode.srcIn),
),
],
),
Container(
height: 32,
padding: EdgeInsets.symmetric(horizontal: 4),
decoration: ShapeDecoration(
color: AppColor.blueLight,
shape: RoundedRectangleBorder(
side: BorderSide(width: 1, color: AppColor.blueLightHover),
borderRadius: BorderRadius.circular(8),
),
),
child: buildRow('تاریخ', '07:15:00 - 1402/07/01'),
),
buildRow('مشخصات فروشنده', 'افلاک - 09203659874'),
buildRow('وزن خریداری شده', '200 کیلوگرم'),
buildRow('لاشه خریداری شده', '200 عدد'),
],
),
);
},
separatorBuilder: (BuildContext context, int index) => SizedBox(height: 6),
itemCount: 3,
),
),*/
],
),
);
}
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),
),
),
],
),
);
}
/* Widget inventoryWidget() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
children: [
const SizedBox(height: 20),
Align(
alignment: Alignment.centerRight,
child: Text(
'خرید های خارج استان',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
),
SizedBox(height: 4),
ObxValue(
(data) => data.isEmpty
? Container(
margin: const EdgeInsets.symmetric(vertical: 2),
height: 80,
padding: EdgeInsets.all(6),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.blueNormal, width: 1),
),
child: Center(child: CircularProgressIndicator()),
)
: ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: controller.rootLogic.inventoryList.length,
separatorBuilder: (context, index) =>
const SizedBox(height: 8),
itemBuilder: (context, index) {
return ObxValue((expand) {
return GestureDetector(
onTap: () {
controller.rootLogic.toggleExpanded(index);
},
behavior: HitTestBehavior.opaque,
child: AnimatedContainer(
onEnd: () {
controller
.rootLogic
.inventoryExpandedList[index] = !controller
.rootLogic
.inventoryExpandedList[index]!;
},
margin: const EdgeInsets.symmetric(vertical: 2),
padding: EdgeInsets.all(6),
curve: Curves.easeInOut,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: AppColor.blueNormal,
width: 1,
),
),
duration: const Duration(seconds: 1),
height: expand.keys.contains(index) ? 250 : 80,
child: inventoryItem(
isExpanded:
expand.keys.contains(index) && expand[index]!,
index: index,
model: controller.rootLogic.inventoryList[index],
),
),
);
}, controller.rootLogic.inventoryExpandedList);
},
),
controller.rootLogic.inventoryList,
),
],
),
);
}*/
/* Widget inventoryItem({
required bool isExpanded,
required int index,
required InventoryModel model,
}) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 8,
children: [
buildRow('نام محصول', model.name ?? ''),
Visibility(
visible: isExpanded,
child: Column(
spacing: 8,
children: [
buildRow('وزن خریدهای دولتی داخل استان (کیلوگرم)', '0326598653'),
buildRow(
'وزن خریدهای آزاد داخل استان (کیلوگرم)',
model.receiveFreeCarcassesWeight.toString(),
),
buildRow(
'وزن خریدهای خارج استان (کیلوگرم)',
model.freeBuyingCarcassesWeight.toString(),
),
buildRow(
'کل ورودی به انبار (کیلوگرم)',
model.totalFreeBarsCarcassesWeight.toString(),
),
buildRow(
'کل فروش (کیلوگرم)',
model.realAllocatedWeight.toString(),
),
buildRow(
'مانده انبار (کیلوگرم)',
model.totalRemainWeight.toString(),
),
],
),
),
],
);
}
Widget allocationsMade() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
children: [
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'تخصیصات صورت گرفته',
style: AppFonts.yekan16Bold.copyWith(
color: AppColor.blueNormal,
),
),
RElevated(
text: 'تایید یکجا',
height: 30,
onPressed: () {
controller.confirmAllAllocations();
},
),
],
),
SizedBox(height: 4),
ObxValue((data) {
if (data.value == null) {
return Container(
height: 80,
margin: const EdgeInsets.all(8),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.blueNormal, width: 1),
),
child: Center(child: CircularProgressIndicator()),
);
} else if (data.value?.results?.isEmpty ?? true) {
return Container(
height: 80,
margin: const EdgeInsets.all(8),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.blueNormal, width: 1),
),
child: Center(child: Text('هیچ تخصیصات صورت نگرفته است ')),
);
} else {
return Container(
margin: const EdgeInsets.symmetric(vertical: 2),
height: 700,
padding: const EdgeInsets.all(6),
child: ListView.separated(
padding: const EdgeInsets.all(8.0),
itemCount: data.value?.results?.length ?? 0,
itemBuilder: (BuildContext context, int index) {
final result = data.value!.results![index];
return Card(
margin: const EdgeInsets.symmetric(vertical: 4.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: const BorderSide(
color: AppColor.blueNormal,
width: 1,
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildRow('ردیف', '${index + 1}'),
buildRow(
'تاریخ ثبت',
result.date!.formattedJalaliDate ?? 'N/A',
),
buildRow(
'نوع تخصیص',
result.allocation_type?.faAllocationType ?? 'N/A',
),
buildRow(
'مشخصات خریدار',
'${result.to_guilds?.user?.fullname} - ${result.to_guilds?.guilds_name}' ??
'N/A',
),
buildRow(
'مشخصات فروشنده',
result.steward?.user?.fullname ?? 'N/A',
),
buildRow(
'نوع فروش',
result.sell_type?.faItem ?? 'N/A',
),
buildRow(
'قیمت هر کیلو',
'${result.amount ?? 0} ریال ',
),
buildRow(
'قیمت کل',
'${result.total_amount ?? 0} ریال',
),
buildRow(
'وزن تخصیصی',
'${result.weight_of_carcasses?.toInt() ?? 0} کیلوگرم',
),
buildRow(
'کداحراز',
result.registration_code?.toString() ?? 'N/A',
),
buildRow(
'وضعیت کد احراز',
result.system_registration_code == true
? "ارسال شده"
: "ارسال نشده" ?? 'N/A',
),
buildRow(
'افت وزن(کیلوگرم)',
result.weight_loss_of_carcasses
?.toInt()
.toString() ??
'N/A',
),
buildRow(
'وضعیت',
result.receiver_state?.faItem ?? 'N/A',
),
Row(
spacing: 10,
children: [
Expanded(
child: RElevated(
height: 40,
text: 'تایید',
onPressed: () {
ConformAllocation confromation =
ConformAllocation(
allocation_key: result.key,
number_of_carcasses:
result.number_of_carcasses,
weight_of_carcasses: result
.weight_of_carcasses
?.toInt(),
amount: result.amount,
total_amount: result.total_amount,
);
controller.confirmAllocation(
confromation,
);
},
),
),
Expanded(
child: RElevated(
height: 40,
backgroundColor: AppColor.error,
text: 'رد',
onPressed: () {
controller.denyAllocation(
result.key ?? '',
);
},
),
),
],
),
],
),
),
);
},
separatorBuilder: (BuildContext context, int index) =>
SizedBox(height: 8),
),
);
}
}, controller.allocatedMadeModel),
],
),
);
}
void showAddBottomSheet() {
Get.bottomSheet(
SafeArea(
child: BaseBottomSheet(
height: 700,
child: Padding(
padding: EdgeInsets.only(
left: 16,
right: 16,
top: 16,
bottom: MediaQuery.of(Get.context!).viewInsets.bottom + 16,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'ثبت توزیع/ فروش',
style: AppFonts.yekan16Bold.copyWith(
color: AppColor.blueNormal,
),
),
const SizedBox(height: 12),
RTextField(
controller: TextEditingController(),
label: 'تاریخ',
enabled: false,
initText: Jalali.now().formatCompactDate(),
),
const SizedBox(height: 12),
Material(
type: MaterialType.transparency,
child: productDropDown(),
),
const SizedBox(height: 12),
SizedBox(
height: 40,
child: ObxValue((data) {
return Row(
children: [
Radio(
value: 1,
groupValue: controller.saleType.value,
onChanged: (value) {
controller.saleType.value = value!;
},
),
Text('فروش اختصاصی', style: AppFonts.yekan14),
SizedBox(width: 12),
Radio(
value: 2,
groupValue: controller.saleType.value,
onChanged: (value) {
controller.saleType.value = value!;
},
),
Text('فروش آزاد', style: AppFonts.yekan14),
],
);
}, controller.saleType),
),
const SizedBox(height: 12),
Material(
type: MaterialType.transparency,
child: guildsDropDown(),
),
const SizedBox(height: 12),
RTextField(
controller: controller.weightController,
keyboardType: TextInputType.number,
onChanged: (p0) {
controller.weight.value = int.tryParse(p0) ?? 0;
},
label: 'وزن لاشه',
),
const SizedBox(height: 12),
RTextField(
controller: controller.pricePerKiloController,
onChanged: (p0) {
controller.pricePerKilo.value = int.tryParse(p0) ?? 0;
},
keyboardType: TextInputType.number,
label: 'قیمت هر کیلو',
),
const SizedBox(height: 12),
ObxValue(
(p0) => RTextField(
enabled: false,
keyboardType: TextInputType.number,
initText: controller.totalCost.value.toString(),
controller: controller.totalCostController,
label: 'هزینه کل',
),
controller.totalCost,
),
const SizedBox(height: 20),
ObxValue((data) {
return RElevated(
text: 'ثبت',
onPressed: data.value
? () {
controller.submitAllocation();
}
: null,
);
}, controller.isValid),
const SizedBox(height: 20),
],
),
),
),
),
isScrollControlled: true,
backgroundColor: Colors.transparent,
);
}
Widget guildsDropDown() {
return ObxValue((p0) {
return DropdownButtonFormField<GuildModel>(
value: controller.selectedGuildModel.value,
decoration: const InputDecoration(
labelText: 'انتخاب مباشر/صنف',
border: OutlineInputBorder(),
),
isExpanded: true,
items: controller.guildsModel.map((guild) {
return DropdownMenuItem<GuildModel>(
value: guild,
child: Text(
'${guild.steward == true ? 'مباشر' : 'صنف'} ${guild.user?.fullname} (${guild.user?.mobile})',
),
);
}).toList(),
onChanged: (value) {
if (value != null) {
controller.setSelectedGuild(value);
controller.checkVerfication();
}
},
);
}, controller.guildsModel);
*/ /* return GetBuilder<SalesWithinProvinceLogic>(
builder: (controller) {
return DropdownButtonFormField<GuildModel>(
value: controller.selectedGuildModel.value,
decoration: const InputDecoration(
labelText: 'انتخاب مباشر/صنف',
border: OutlineInputBorder(),
),
isExpanded: true,
items: controller.guildsModel.map((guild) {
return DropdownMenuItem<GuildModel>(
value: guild,
child: Text(
'${guild.steward == true ? 'مباشر' : 'صنف'} ${guild.user
?.fullname} (${guild.user?.mobile})',
),
);
}).toList(),
onChanged: (value) {
if (value != null) {
controller.setSelectedGuild(value);
}
},
);
},
);*/ /*
}
Widget productDropDown() {
return GetBuilder<SalesWithOutProvinceLogic>(
builder: (controller) {
return DropdownButtonFormField<ProductModel>(
value: controller.selectedProductModel.value,
decoration: const InputDecoration(
labelText: 'انتخاب محصول',
border: OutlineInputBorder(),
),
isExpanded: true,
items: controller.rolesProductsModel.map((guild) {
return DropdownMenuItem<ProductModel>(
value: guild,
child: Text('${guild.name}'),
);
}).toList(),
onChanged: (value) {
if (value != null) {
controller.setSelectedProduct(value);
controller.checkVerfication();
}
},
);
},
);
}*/
}