204 lines
6.2 KiB
Dart
204 lines
6.2 KiB
Dart
import 'dart:developer';
|
|
|
|
import 'package:injectable/injectable.dart';
|
|
import 'package:isar/isar.dart';
|
|
import 'package:mnemo_cards_backend/discounts/discount_campaign_ext.dart';
|
|
import 'package:mnemo_cards_common_backend/mnemo_cards_common_backend.dart';
|
|
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
|
|
|
|
import '../main.dart';
|
|
|
|
@lazySingleton
|
|
class DiscountsManager {
|
|
Future<void> applyDiscount({
|
|
required Iterable<DiscountModel> discounts,
|
|
required UserModel user,
|
|
}) async {
|
|
await isar.writeTxn(() async {
|
|
await user.userData.load();
|
|
final userData = user.userData.value!;
|
|
userData.activeDiscounts.addAll(discounts);
|
|
await user.userData.save();
|
|
});
|
|
}
|
|
|
|
Future<void> changeCampaignStatus(DiscountCampaignModel campaign) async {
|
|
final now = DateTime.now();
|
|
var target = campaign.status;
|
|
if (campaign.status == DiscountCampaignModelStatus.created &&
|
|
now.isBetween(campaign.start, campaign.finish)) {
|
|
target = DiscountCampaignModelStatus.active;
|
|
} else if (campaign.status == DiscountCampaignModelStatus.active) {
|
|
if (now.isBefore(campaign.start)) {
|
|
target = DiscountCampaignModelStatus.created;
|
|
} else if (now.isAfter(campaign.finish)) {
|
|
target = DiscountCampaignModelStatus.expired;
|
|
}
|
|
}
|
|
if (target != campaign.status) {
|
|
await isar.writeTxn(() => isar.discountCampaignModels.put(
|
|
campaign.copyWith(status: target),
|
|
));
|
|
}
|
|
}
|
|
|
|
Future<DiscountError?> applyCampaign(DiscountCampaignModel campaign) async {
|
|
final now = DateTime.now();
|
|
if (!now.isBetween(campaign.start, campaign.finish)) {
|
|
if (now.isBefore(campaign.start)) {
|
|
return DiscountError(DiscountErrorType.notStarted);
|
|
}
|
|
return DiscountError(DiscountErrorType.expired);
|
|
}
|
|
// final usersData = await isar.txn(
|
|
// () => isar.userDataModels
|
|
// .filter()
|
|
// .optional(
|
|
// campaign.tags.isNotEmpty,
|
|
// (q) => q.anyOf(
|
|
// campaign.tags,
|
|
// (q, tag) => q.tagsElementContains(tag),
|
|
// ),
|
|
// )
|
|
// .findAll(),
|
|
// );
|
|
return null;
|
|
}
|
|
|
|
Future<void> removeDiscount({
|
|
required DiscountCampaignModel campaign,
|
|
required UserModel user,
|
|
}) async {
|
|
await isar.writeTxn(() async {
|
|
await user.userData.load();
|
|
final userData = user.userData.value!;
|
|
userData.activeDiscounts.removeAll(campaign.discounts);
|
|
await isar.userDataModels.put(userData);
|
|
});
|
|
}
|
|
|
|
Future<double> getProductDiscount(
|
|
MnemoCardsProductModel model,
|
|
UserDataModel userData,
|
|
) async {
|
|
double maxDiscount = 0;
|
|
for (final discount in userData.activeDiscounts) {
|
|
if (discount.discountPercent > maxDiscount &&
|
|
discount.products.any((p) => p.equalsProduct(model))) {
|
|
maxDiscount = discount.discountPercent;
|
|
}
|
|
}
|
|
|
|
final activeCampaigns =
|
|
await discountCampaignsForUser(userData, product: model);
|
|
for (final campaign in activeCampaigns) {
|
|
for (final discount in campaign.discounts) {
|
|
if (discount.discountPercent > maxDiscount &&
|
|
discount.products.any((p) => p.equalsProduct(model))) {
|
|
maxDiscount = discount.discountPercent;
|
|
}
|
|
}
|
|
}
|
|
return maxDiscount;
|
|
}
|
|
|
|
Future<List<DiscountCampaignModel>> discountCampaignsForUser(
|
|
UserDataModel userModel, {
|
|
MnemoCardsProductModel? product,
|
|
}) async {
|
|
final activeCampaigns =
|
|
await isar.txn(() async => isar.discountCampaignModels
|
|
.filter()
|
|
.statusEqualTo(DiscountCampaignModelStatus.active)
|
|
.optional(userModel.tags.isEmpty, (q) => q.tagsIsEmpty())
|
|
.optional(
|
|
product != null,
|
|
(q) => q.discounts(
|
|
(d) => d.productsElement(
|
|
(p) => p.typeEqualTo(product!.type).productIdEqualTo(
|
|
product.id,
|
|
),
|
|
),
|
|
),
|
|
)
|
|
.findAll());
|
|
if (userModel.tags.isEmpty) {
|
|
return activeCampaigns;
|
|
} else {
|
|
// todo check tags in query
|
|
final userTags = userModel.tags.toSet();
|
|
return activeCampaigns
|
|
.where((campaign) => campaign.tags.hasIntersection(userTags))
|
|
.toList();
|
|
}
|
|
}
|
|
|
|
Future<List<DiscountCampaignDto>> discountCampaigns() async {
|
|
final models = await isar
|
|
.txn(() async => isar.discountCampaignModels.where().findAll());
|
|
final dtos = await Future.wait(models.map((m) async => await m.toDto()));
|
|
return dtos;
|
|
}
|
|
|
|
Future<String?> deleteDiscountCampaign(String stringId) async {
|
|
try {
|
|
final id = int.parse(stringId);
|
|
isar.writeTxn(() async {
|
|
final model = await isar.discountCampaignModels.get(id);
|
|
if (model == null) {
|
|
return 'Campaign $id not found';
|
|
}
|
|
if (model.status != DiscountCampaignModelStatus.disabled) {
|
|
return 'Disable campaign before deleting';
|
|
}
|
|
isar.discountCampaignModels.delete(id);
|
|
});
|
|
return null;
|
|
} catch (e, s) {
|
|
log('Error when deleting discount campaign', error: e, stackTrace: s);
|
|
return 'Error $e';
|
|
}
|
|
}
|
|
|
|
Future<bool> addDiscount(DiscountCampaignDto dto) async {
|
|
try {
|
|
final model = DiscountCampaignModel(
|
|
id: dto.id,
|
|
start: dto.start,
|
|
finish: dto.finish,
|
|
status: dto.status.toModel(),
|
|
name: dto.name,
|
|
tags: dto.tags,
|
|
);
|
|
final discounts = dto.discounts.map((d) => d.toModel()).toList();
|
|
await isar.writeTxn(() async {
|
|
await isar.discountModels.putAll(discounts);
|
|
await isar.discountCampaignModels.put(model);
|
|
await model.discounts.reset();
|
|
model.discounts.addAll(discounts);
|
|
await model.discounts.save();
|
|
});
|
|
|
|
return true;
|
|
} catch (e, s) {
|
|
print('error when adding campaign');
|
|
log('error when adding campaign', error: e, stackTrace: s);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
const DiscountsManager();
|
|
}
|
|
|
|
class DiscountError {
|
|
final String? message;
|
|
final DiscountErrorType type;
|
|
|
|
DiscountError(this.type, {this.message});
|
|
}
|
|
|
|
enum DiscountErrorType {
|
|
notAvailable,
|
|
notStarted,
|
|
expired,
|
|
}
|