@blackcode_sa/metaestetics-api 1.15.13 → 1.15.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -155,9 +155,7 @@ __export(index_exports, {
155
155
  USER_FORMS_SUBCOLLECTION: () => USER_FORMS_SUBCOLLECTION,
156
156
  UserRole: () => UserRole,
157
157
  UserService: () => UserService,
158
- enforceAppointmentLimit: () => enforceAppointmentLimit,
159
158
  enforceBranchLimit: () => enforceBranchLimit,
160
- enforceMessageLimit: () => enforceMessageLimit,
161
159
  enforceProcedureLimit: () => enforceProcedureLimit,
162
160
  enforceProviderLimit: () => enforceProviderLimit,
163
161
  getEffectiveTier: () => getEffectiveTier,
@@ -12736,10 +12734,8 @@ var TIER_CONFIG = {
12736
12734
  tier: "free",
12737
12735
  name: "Free",
12738
12736
  limits: {
12739
- maxProviders: 1,
12740
- maxProcedures: 3,
12741
- maxAppointmentsPerMonth: 3,
12742
- maxMessagesPerMonth: 10,
12737
+ maxProvidersPerBranch: 1,
12738
+ maxProceduresPerProvider: 3,
12743
12739
  maxBranches: 1
12744
12740
  }
12745
12741
  },
@@ -12747,10 +12743,8 @@ var TIER_CONFIG = {
12747
12743
  tier: "connect",
12748
12744
  name: "Connect",
12749
12745
  limits: {
12750
- maxProviders: -1,
12751
- maxProcedures: 15,
12752
- maxAppointmentsPerMonth: 100,
12753
- maxMessagesPerMonth: -1,
12746
+ maxProvidersPerBranch: 3,
12747
+ maxProceduresPerProvider: 10,
12754
12748
  maxBranches: 1
12755
12749
  }
12756
12750
  },
@@ -12758,11 +12752,9 @@ var TIER_CONFIG = {
12758
12752
  tier: "pro",
12759
12753
  name: "Pro",
12760
12754
  limits: {
12761
- maxProviders: -1,
12762
- maxProcedures: -1,
12763
- maxAppointmentsPerMonth: -1,
12764
- maxMessagesPerMonth: -1,
12765
- maxBranches: -1
12755
+ maxProvidersPerBranch: 10,
12756
+ maxProceduresPerProvider: 20,
12757
+ maxBranches: 3
12766
12758
  }
12767
12759
  }
12768
12760
  };
@@ -12893,8 +12885,10 @@ function resolveEffectiveTier(subscriptionModel) {
12893
12885
  var TierLimitError = class extends Error {
12894
12886
  constructor(resource, currentTier, currentCount, maxAllowed) {
12895
12887
  const tierLabel = currentTier.charAt(0).toUpperCase() + currentTier.slice(1);
12888
+ const canBuyAddons = currentTier === "connect" || currentTier === "pro";
12889
+ const actionHint = canBuyAddons ? "Please upgrade your plan or purchase an add-on." : "Please upgrade to Connect or Pro to add more.";
12896
12890
  super(
12897
- `Your ${tierLabel} plan allows a maximum of ${maxAllowed} ${resource}. You currently have ${currentCount}. Please upgrade your plan to add more.`
12891
+ `Your ${tierLabel} plan allows a maximum of ${maxAllowed} ${resource}. You currently have ${currentCount}. ${actionHint}`
12898
12892
  );
12899
12893
  this.code = "TIER_LIMIT_EXCEEDED";
12900
12894
  this.name = "TierLimitError";
@@ -12904,62 +12898,49 @@ var TierLimitError = class extends Error {
12904
12898
  this.maxAllowed = maxAllowed;
12905
12899
  }
12906
12900
  };
12907
- async function getEffectiveTier(db, clinicGroupId) {
12901
+ async function getClinicGroupTierData(db, clinicGroupId) {
12908
12902
  const groupRef = (0, import_firestore35.doc)(db, CLINIC_GROUPS_COLLECTION, clinicGroupId);
12909
12903
  const groupSnap = await (0, import_firestore35.getDoc)(groupRef);
12910
12904
  if (!groupSnap.exists()) {
12911
12905
  throw new Error(`Clinic group ${clinicGroupId} not found`);
12912
12906
  }
12913
- const subscriptionModel = groupSnap.data().subscriptionModel || "no_subscription";
12914
- return resolveEffectiveTier(subscriptionModel);
12907
+ const data = groupSnap.data();
12908
+ const subscriptionModel = data.subscriptionModel || "no_subscription";
12909
+ return {
12910
+ tier: resolveEffectiveTier(subscriptionModel),
12911
+ billing: data.billing
12912
+ };
12915
12913
  }
12916
- async function countProvidersInGroup(db, clinicGroupId) {
12917
- const clinicsQuery = (0, import_firestore35.query)(
12918
- (0, import_firestore35.collection)(db, CLINICS_COLLECTION),
12919
- (0, import_firestore35.where)("clinicGroupId", "==", clinicGroupId),
12920
- (0, import_firestore35.where)("isActive", "==", true)
12921
- );
12922
- const clinicsSnap = await (0, import_firestore35.getDocs)(clinicsQuery);
12923
- const clinicIds = clinicsSnap.docs.map((d) => d.id);
12924
- if (clinicIds.length === 0) return 0;
12914
+ async function getEffectiveTier(db, clinicGroupId) {
12915
+ const { tier } = await getClinicGroupTierData(db, clinicGroupId);
12916
+ return tier;
12917
+ }
12918
+ async function countProvidersInBranch(db, branchId) {
12925
12919
  const practitionersQuery = (0, import_firestore35.query)(
12926
12920
  (0, import_firestore35.collection)(db, PRACTITIONERS_COLLECTION),
12927
12921
  (0, import_firestore35.where)("isActive", "==", true)
12928
12922
  );
12929
12923
  const practitionersSnap = await (0, import_firestore35.getDocs)(practitionersQuery);
12930
- const clinicIdSet = new Set(clinicIds);
12931
- const uniqueProviders = practitionersSnap.docs.filter((d) => {
12932
- const data = d.data();
12933
- const clinics = data.clinics || [];
12934
- return clinics.some((c) => clinicIdSet.has(c));
12935
- });
12936
- return uniqueProviders.length;
12924
+ return practitionersSnap.docs.filter((d) => {
12925
+ const clinics = d.data().clinics || [];
12926
+ return clinics.includes(branchId);
12927
+ }).length;
12937
12928
  }
12938
- async function countProceduresInGroup(db, clinicGroupId) {
12939
- const clinicsQuery = (0, import_firestore35.query)(
12940
- (0, import_firestore35.collection)(db, CLINICS_COLLECTION),
12941
- (0, import_firestore35.where)("clinicGroupId", "==", clinicGroupId),
12929
+ async function countProceduresForProvider(db, branchId, providerId) {
12930
+ const proceduresQuery = (0, import_firestore35.query)(
12931
+ (0, import_firestore35.collection)(db, PROCEDURES_COLLECTION),
12932
+ (0, import_firestore35.where)("clinicBranchId", "==", branchId),
12933
+ (0, import_firestore35.where)("practitionerId", "==", providerId),
12942
12934
  (0, import_firestore35.where)("isActive", "==", true)
12943
12935
  );
12944
- const clinicsSnap = await (0, import_firestore35.getDocs)(clinicsQuery);
12945
- const clinicIds = clinicsSnap.docs.map((d) => d.id);
12946
- if (clinicIds.length === 0) return 0;
12936
+ const proceduresSnap = await (0, import_firestore35.getDocs)(proceduresQuery);
12947
12937
  const uniqueTechnologyIds = /* @__PURE__ */ new Set();
12948
- for (let i = 0; i < clinicIds.length; i += 30) {
12949
- const batch = clinicIds.slice(i, i + 30);
12950
- const proceduresQuery = (0, import_firestore35.query)(
12951
- (0, import_firestore35.collection)(db, PROCEDURES_COLLECTION),
12952
- (0, import_firestore35.where)("clinicBranchId", "in", batch),
12953
- (0, import_firestore35.where)("isActive", "==", true)
12954
- );
12955
- const proceduresSnap = await (0, import_firestore35.getDocs)(proceduresQuery);
12956
- proceduresSnap.docs.forEach((d) => {
12957
- const technologyId = d.data().technologyId;
12958
- if (technologyId) {
12959
- uniqueTechnologyIds.add(technologyId);
12960
- }
12961
- });
12962
- }
12938
+ proceduresSnap.docs.forEach((d) => {
12939
+ const technologyId = d.data().technologyId;
12940
+ if (technologyId) {
12941
+ uniqueTechnologyIds.add(technologyId);
12942
+ }
12943
+ });
12963
12944
  return uniqueTechnologyIds.size;
12964
12945
  }
12965
12946
  async function countBranchesInGroup(db, clinicGroupId) {
@@ -12971,75 +12952,47 @@ async function countBranchesInGroup(db, clinicGroupId) {
12971
12952
  const clinicsSnap = await (0, import_firestore35.getDocs)(clinicsQuery);
12972
12953
  return clinicsSnap.size;
12973
12954
  }
12974
- async function enforceProviderLimit(db, clinicGroupId) {
12975
- const tier = await getEffectiveTier(db, clinicGroupId);
12955
+ async function enforceProviderLimit(db, clinicGroupId, branchId) {
12956
+ var _a;
12957
+ const { tier, billing } = await getClinicGroupTierData(db, clinicGroupId);
12976
12958
  const config = TIER_CONFIG[tier];
12977
12959
  if (!config) return;
12978
- const max = config.limits.maxProviders;
12979
- if (max === -1) return;
12980
- const currentCount = await countProvidersInGroup(db, clinicGroupId);
12981
- if (currentCount + 1 > max) {
12982
- throw new TierLimitError("providers", tier, currentCount, max);
12960
+ const baseMax = config.limits.maxProvidersPerBranch;
12961
+ if (baseMax === -1) return;
12962
+ const addOns = (billing == null ? void 0 : billing.addOns) || {};
12963
+ const extraProviders = ((_a = addOns[branchId]) == null ? void 0 : _a.extraProviders) || 0;
12964
+ const effectiveMax = baseMax + extraProviders;
12965
+ const currentCount = await countProvidersInBranch(db, branchId);
12966
+ if (currentCount + 1 > effectiveMax) {
12967
+ throw new TierLimitError("providers in this branch", tier, currentCount, effectiveMax);
12983
12968
  }
12984
12969
  }
12985
- async function enforceProcedureLimit(db, clinicGroupId, count = 1) {
12986
- const tier = await getEffectiveTier(db, clinicGroupId);
12970
+ async function enforceProcedureLimit(db, clinicGroupId, branchId, providerId, count = 1) {
12971
+ var _a;
12972
+ const { tier, billing } = await getClinicGroupTierData(db, clinicGroupId);
12987
12973
  const config = TIER_CONFIG[tier];
12988
12974
  if (!config) return;
12989
- const max = config.limits.maxProcedures;
12990
- if (max === -1) return;
12991
- const currentCount = await countProceduresInGroup(db, clinicGroupId);
12992
- if (currentCount + count > max) {
12993
- throw new TierLimitError("procedures", tier, currentCount, max);
12975
+ const baseMax = config.limits.maxProceduresPerProvider;
12976
+ if (baseMax === -1) return;
12977
+ const addOns = (billing == null ? void 0 : billing.addOns) || {};
12978
+ const procedureBlocks = ((_a = addOns[branchId]) == null ? void 0 : _a.procedureBlocks) || 0;
12979
+ const effectiveMax = baseMax + procedureBlocks * 10;
12980
+ const currentCount = await countProceduresForProvider(db, branchId, providerId);
12981
+ if (currentCount + count > effectiveMax) {
12982
+ throw new TierLimitError("procedures for this provider", tier, currentCount, effectiveMax);
12994
12983
  }
12995
12984
  }
12996
12985
  async function enforceBranchLimit(db, clinicGroupId) {
12997
- const tier = await getEffectiveTier(db, clinicGroupId);
12986
+ const { tier, billing } = await getClinicGroupTierData(db, clinicGroupId);
12998
12987
  const config = TIER_CONFIG[tier];
12999
12988
  if (!config) return;
13000
- const max = config.limits.maxBranches;
13001
- if (max === -1) return;
12989
+ const baseMax = config.limits.maxBranches;
12990
+ if (baseMax === -1) return;
12991
+ const branchAddonCount = (billing == null ? void 0 : billing.branchAddonCount) || 0;
12992
+ const effectiveMax = baseMax + branchAddonCount;
13002
12993
  const currentCount = await countBranchesInGroup(db, clinicGroupId);
13003
- if (currentCount + 1 > max) {
13004
- throw new TierLimitError("clinic branches", tier, currentCount, max);
13005
- }
13006
- }
13007
- async function enforceAppointmentLimit(db, clinicGroupId) {
13008
- var _a;
13009
- const tier = await getEffectiveTier(db, clinicGroupId);
13010
- const config = TIER_CONFIG[tier];
13011
- if (!config) return;
13012
- const max = config.limits.maxAppointmentsPerMonth;
13013
- if (max === -1) return;
13014
- const now = /* @__PURE__ */ new Date();
13015
- const yearMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
13016
- const counterRef = (0, import_firestore35.doc)(
13017
- db,
13018
- `${CLINIC_GROUPS_COLLECTION}/${clinicGroupId}/usage_counters/${yearMonth}`
13019
- );
13020
- const counterSnap = await (0, import_firestore35.getDoc)(counterRef);
13021
- const currentCount = counterSnap.exists() ? ((_a = counterSnap.data()) == null ? void 0 : _a.appointmentsCreated) || 0 : 0;
13022
- if (currentCount + 1 > max) {
13023
- throw new TierLimitError("appointments this month", tier, currentCount, max);
13024
- }
13025
- }
13026
- async function enforceMessageLimit(db, clinicGroupId) {
13027
- var _a;
13028
- const tier = await getEffectiveTier(db, clinicGroupId);
13029
- const config = TIER_CONFIG[tier];
13030
- if (!config) return;
13031
- const max = config.limits.maxMessagesPerMonth;
13032
- if (max === -1) return;
13033
- const now = /* @__PURE__ */ new Date();
13034
- const yearMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
13035
- const counterRef = (0, import_firestore35.doc)(
13036
- db,
13037
- `${CLINIC_GROUPS_COLLECTION}/${clinicGroupId}/usage_counters/${yearMonth}`
13038
- );
13039
- const counterSnap = await (0, import_firestore35.getDoc)(counterRef);
13040
- const currentCount = counterSnap.exists() ? ((_a = counterSnap.data()) == null ? void 0 : _a.messagesCount) || 0 : 0;
13041
- if (currentCount + 1 > max) {
13042
- throw new TierLimitError("messages this month", tier, currentCount, max);
12994
+ if (currentCount + 1 > effectiveMax) {
12995
+ throw new TierLimitError("clinic branches", tier, currentCount, effectiveMax);
13043
12996
  }
13044
12997
  }
13045
12998
 
@@ -13295,7 +13248,7 @@ var PractitionerService = class extends BaseService {
13295
13248
  if (clinicSnap.exists()) {
13296
13249
  const clinicGroupId = clinicSnap.data().clinicGroupId;
13297
13250
  if (clinicGroupId) {
13298
- await enforceProviderLimit(this.db, clinicGroupId);
13251
+ await enforceProviderLimit(this.db, clinicGroupId, validData.clinics[0]);
13299
13252
  }
13300
13253
  }
13301
13254
  }
@@ -13375,7 +13328,7 @@ var PractitionerService = class extends BaseService {
13375
13328
  throw new Error(`Clinic ${clinicId} not found`);
13376
13329
  }
13377
13330
  if (clinic.clinicGroupId) {
13378
- await enforceProviderLimit(this.db, clinic.clinicGroupId);
13331
+ await enforceProviderLimit(this.db, clinic.clinicGroupId, clinicId);
13379
13332
  }
13380
13333
  const clinicsToAdd = /* @__PURE__ */ new Set([clinicId]);
13381
13334
  if (data.clinics && data.clinics.length > 0) {
@@ -23166,7 +23119,7 @@ var ProcedureService = class extends BaseService {
23166
23119
  throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
23167
23120
  }
23168
23121
  const clinic = clinicSnapshot.data();
23169
- await enforceProcedureLimit(this.db, clinic.clinicGroupId);
23122
+ await enforceProcedureLimit(this.db, clinic.clinicGroupId, validatedData.clinicBranchId, validatedData.practitionerId);
23170
23123
  const practitionerRef = (0, import_firestore63.doc)(this.db, PRACTITIONERS_COLLECTION, validatedData.practitionerId);
23171
23124
  const practitionerSnapshot = await (0, import_firestore63.getDoc)(practitionerRef);
23172
23125
  if (!practitionerSnapshot.exists()) {
@@ -23573,7 +23526,9 @@ var ProcedureService = class extends BaseService {
23573
23526
  throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
23574
23527
  }
23575
23528
  const clinic = clinicSnapshot.data();
23576
- await enforceProcedureLimit(this.db, clinic.clinicGroupId, practitionerIds.length);
23529
+ for (const practitionerId of practitionerIds) {
23530
+ await enforceProcedureLimit(this.db, clinic.clinicGroupId, validatedData.clinicBranchId, practitionerId);
23531
+ }
23577
23532
  let processedPhotos = [];
23578
23533
  if (validatedData.photos && validatedData.photos.length > 0) {
23579
23534
  const batchId = this.generateId();
@@ -28051,9 +28006,7 @@ var RequirementType = /* @__PURE__ */ ((RequirementType2) => {
28051
28006
  USER_FORMS_SUBCOLLECTION,
28052
28007
  UserRole,
28053
28008
  UserService,
28054
- enforceAppointmentLimit,
28055
28009
  enforceBranchLimit,
28056
- enforceMessageLimit,
28057
28010
  enforceProcedureLimit,
28058
28011
  enforceProviderLimit,
28059
28012
  getEffectiveTier,
package/dist/index.mjs CHANGED
@@ -12752,10 +12752,8 @@ var TIER_CONFIG = {
12752
12752
  tier: "free",
12753
12753
  name: "Free",
12754
12754
  limits: {
12755
- maxProviders: 1,
12756
- maxProcedures: 3,
12757
- maxAppointmentsPerMonth: 3,
12758
- maxMessagesPerMonth: 10,
12755
+ maxProvidersPerBranch: 1,
12756
+ maxProceduresPerProvider: 3,
12759
12757
  maxBranches: 1
12760
12758
  }
12761
12759
  },
@@ -12763,10 +12761,8 @@ var TIER_CONFIG = {
12763
12761
  tier: "connect",
12764
12762
  name: "Connect",
12765
12763
  limits: {
12766
- maxProviders: -1,
12767
- maxProcedures: 15,
12768
- maxAppointmentsPerMonth: 100,
12769
- maxMessagesPerMonth: -1,
12764
+ maxProvidersPerBranch: 3,
12765
+ maxProceduresPerProvider: 10,
12770
12766
  maxBranches: 1
12771
12767
  }
12772
12768
  },
@@ -12774,11 +12770,9 @@ var TIER_CONFIG = {
12774
12770
  tier: "pro",
12775
12771
  name: "Pro",
12776
12772
  limits: {
12777
- maxProviders: -1,
12778
- maxProcedures: -1,
12779
- maxAppointmentsPerMonth: -1,
12780
- maxMessagesPerMonth: -1,
12781
- maxBranches: -1
12773
+ maxProvidersPerBranch: 10,
12774
+ maxProceduresPerProvider: 20,
12775
+ maxBranches: 3
12782
12776
  }
12783
12777
  }
12784
12778
  };
@@ -12909,8 +12903,10 @@ function resolveEffectiveTier(subscriptionModel) {
12909
12903
  var TierLimitError = class extends Error {
12910
12904
  constructor(resource, currentTier, currentCount, maxAllowed) {
12911
12905
  const tierLabel = currentTier.charAt(0).toUpperCase() + currentTier.slice(1);
12906
+ const canBuyAddons = currentTier === "connect" || currentTier === "pro";
12907
+ const actionHint = canBuyAddons ? "Please upgrade your plan or purchase an add-on." : "Please upgrade to Connect or Pro to add more.";
12912
12908
  super(
12913
- `Your ${tierLabel} plan allows a maximum of ${maxAllowed} ${resource}. You currently have ${currentCount}. Please upgrade your plan to add more.`
12909
+ `Your ${tierLabel} plan allows a maximum of ${maxAllowed} ${resource}. You currently have ${currentCount}. ${actionHint}`
12914
12910
  );
12915
12911
  this.code = "TIER_LIMIT_EXCEEDED";
12916
12912
  this.name = "TierLimitError";
@@ -12920,62 +12916,49 @@ var TierLimitError = class extends Error {
12920
12916
  this.maxAllowed = maxAllowed;
12921
12917
  }
12922
12918
  };
12923
- async function getEffectiveTier(db, clinicGroupId) {
12919
+ async function getClinicGroupTierData(db, clinicGroupId) {
12924
12920
  const groupRef = doc24(db, CLINIC_GROUPS_COLLECTION, clinicGroupId);
12925
12921
  const groupSnap = await getDoc26(groupRef);
12926
12922
  if (!groupSnap.exists()) {
12927
12923
  throw new Error(`Clinic group ${clinicGroupId} not found`);
12928
12924
  }
12929
- const subscriptionModel = groupSnap.data().subscriptionModel || "no_subscription";
12930
- return resolveEffectiveTier(subscriptionModel);
12925
+ const data = groupSnap.data();
12926
+ const subscriptionModel = data.subscriptionModel || "no_subscription";
12927
+ return {
12928
+ tier: resolveEffectiveTier(subscriptionModel),
12929
+ billing: data.billing
12930
+ };
12931
12931
  }
12932
- async function countProvidersInGroup(db, clinicGroupId) {
12933
- const clinicsQuery = query13(
12934
- collection13(db, CLINICS_COLLECTION),
12935
- where13("clinicGroupId", "==", clinicGroupId),
12936
- where13("isActive", "==", true)
12937
- );
12938
- const clinicsSnap = await getDocs13(clinicsQuery);
12939
- const clinicIds = clinicsSnap.docs.map((d) => d.id);
12940
- if (clinicIds.length === 0) return 0;
12932
+ async function getEffectiveTier(db, clinicGroupId) {
12933
+ const { tier } = await getClinicGroupTierData(db, clinicGroupId);
12934
+ return tier;
12935
+ }
12936
+ async function countProvidersInBranch(db, branchId) {
12941
12937
  const practitionersQuery = query13(
12942
12938
  collection13(db, PRACTITIONERS_COLLECTION),
12943
12939
  where13("isActive", "==", true)
12944
12940
  );
12945
12941
  const practitionersSnap = await getDocs13(practitionersQuery);
12946
- const clinicIdSet = new Set(clinicIds);
12947
- const uniqueProviders = practitionersSnap.docs.filter((d) => {
12948
- const data = d.data();
12949
- const clinics = data.clinics || [];
12950
- return clinics.some((c) => clinicIdSet.has(c));
12951
- });
12952
- return uniqueProviders.length;
12942
+ return practitionersSnap.docs.filter((d) => {
12943
+ const clinics = d.data().clinics || [];
12944
+ return clinics.includes(branchId);
12945
+ }).length;
12953
12946
  }
12954
- async function countProceduresInGroup(db, clinicGroupId) {
12955
- const clinicsQuery = query13(
12956
- collection13(db, CLINICS_COLLECTION),
12957
- where13("clinicGroupId", "==", clinicGroupId),
12947
+ async function countProceduresForProvider(db, branchId, providerId) {
12948
+ const proceduresQuery = query13(
12949
+ collection13(db, PROCEDURES_COLLECTION),
12950
+ where13("clinicBranchId", "==", branchId),
12951
+ where13("practitionerId", "==", providerId),
12958
12952
  where13("isActive", "==", true)
12959
12953
  );
12960
- const clinicsSnap = await getDocs13(clinicsQuery);
12961
- const clinicIds = clinicsSnap.docs.map((d) => d.id);
12962
- if (clinicIds.length === 0) return 0;
12954
+ const proceduresSnap = await getDocs13(proceduresQuery);
12963
12955
  const uniqueTechnologyIds = /* @__PURE__ */ new Set();
12964
- for (let i = 0; i < clinicIds.length; i += 30) {
12965
- const batch = clinicIds.slice(i, i + 30);
12966
- const proceduresQuery = query13(
12967
- collection13(db, PROCEDURES_COLLECTION),
12968
- where13("clinicBranchId", "in", batch),
12969
- where13("isActive", "==", true)
12970
- );
12971
- const proceduresSnap = await getDocs13(proceduresQuery);
12972
- proceduresSnap.docs.forEach((d) => {
12973
- const technologyId = d.data().technologyId;
12974
- if (technologyId) {
12975
- uniqueTechnologyIds.add(technologyId);
12976
- }
12977
- });
12978
- }
12956
+ proceduresSnap.docs.forEach((d) => {
12957
+ const technologyId = d.data().technologyId;
12958
+ if (technologyId) {
12959
+ uniqueTechnologyIds.add(technologyId);
12960
+ }
12961
+ });
12979
12962
  return uniqueTechnologyIds.size;
12980
12963
  }
12981
12964
  async function countBranchesInGroup(db, clinicGroupId) {
@@ -12987,75 +12970,47 @@ async function countBranchesInGroup(db, clinicGroupId) {
12987
12970
  const clinicsSnap = await getDocs13(clinicsQuery);
12988
12971
  return clinicsSnap.size;
12989
12972
  }
12990
- async function enforceProviderLimit(db, clinicGroupId) {
12991
- const tier = await getEffectiveTier(db, clinicGroupId);
12973
+ async function enforceProviderLimit(db, clinicGroupId, branchId) {
12974
+ var _a;
12975
+ const { tier, billing } = await getClinicGroupTierData(db, clinicGroupId);
12992
12976
  const config = TIER_CONFIG[tier];
12993
12977
  if (!config) return;
12994
- const max = config.limits.maxProviders;
12995
- if (max === -1) return;
12996
- const currentCount = await countProvidersInGroup(db, clinicGroupId);
12997
- if (currentCount + 1 > max) {
12998
- throw new TierLimitError("providers", tier, currentCount, max);
12978
+ const baseMax = config.limits.maxProvidersPerBranch;
12979
+ if (baseMax === -1) return;
12980
+ const addOns = (billing == null ? void 0 : billing.addOns) || {};
12981
+ const extraProviders = ((_a = addOns[branchId]) == null ? void 0 : _a.extraProviders) || 0;
12982
+ const effectiveMax = baseMax + extraProviders;
12983
+ const currentCount = await countProvidersInBranch(db, branchId);
12984
+ if (currentCount + 1 > effectiveMax) {
12985
+ throw new TierLimitError("providers in this branch", tier, currentCount, effectiveMax);
12999
12986
  }
13000
12987
  }
13001
- async function enforceProcedureLimit(db, clinicGroupId, count = 1) {
13002
- const tier = await getEffectiveTier(db, clinicGroupId);
12988
+ async function enforceProcedureLimit(db, clinicGroupId, branchId, providerId, count = 1) {
12989
+ var _a;
12990
+ const { tier, billing } = await getClinicGroupTierData(db, clinicGroupId);
13003
12991
  const config = TIER_CONFIG[tier];
13004
12992
  if (!config) return;
13005
- const max = config.limits.maxProcedures;
13006
- if (max === -1) return;
13007
- const currentCount = await countProceduresInGroup(db, clinicGroupId);
13008
- if (currentCount + count > max) {
13009
- throw new TierLimitError("procedures", tier, currentCount, max);
12993
+ const baseMax = config.limits.maxProceduresPerProvider;
12994
+ if (baseMax === -1) return;
12995
+ const addOns = (billing == null ? void 0 : billing.addOns) || {};
12996
+ const procedureBlocks = ((_a = addOns[branchId]) == null ? void 0 : _a.procedureBlocks) || 0;
12997
+ const effectiveMax = baseMax + procedureBlocks * 10;
12998
+ const currentCount = await countProceduresForProvider(db, branchId, providerId);
12999
+ if (currentCount + count > effectiveMax) {
13000
+ throw new TierLimitError("procedures for this provider", tier, currentCount, effectiveMax);
13010
13001
  }
13011
13002
  }
13012
13003
  async function enforceBranchLimit(db, clinicGroupId) {
13013
- const tier = await getEffectiveTier(db, clinicGroupId);
13004
+ const { tier, billing } = await getClinicGroupTierData(db, clinicGroupId);
13014
13005
  const config = TIER_CONFIG[tier];
13015
13006
  if (!config) return;
13016
- const max = config.limits.maxBranches;
13017
- if (max === -1) return;
13007
+ const baseMax = config.limits.maxBranches;
13008
+ if (baseMax === -1) return;
13009
+ const branchAddonCount = (billing == null ? void 0 : billing.branchAddonCount) || 0;
13010
+ const effectiveMax = baseMax + branchAddonCount;
13018
13011
  const currentCount = await countBranchesInGroup(db, clinicGroupId);
13019
- if (currentCount + 1 > max) {
13020
- throw new TierLimitError("clinic branches", tier, currentCount, max);
13021
- }
13022
- }
13023
- async function enforceAppointmentLimit(db, clinicGroupId) {
13024
- var _a;
13025
- const tier = await getEffectiveTier(db, clinicGroupId);
13026
- const config = TIER_CONFIG[tier];
13027
- if (!config) return;
13028
- const max = config.limits.maxAppointmentsPerMonth;
13029
- if (max === -1) return;
13030
- const now = /* @__PURE__ */ new Date();
13031
- const yearMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
13032
- const counterRef = doc24(
13033
- db,
13034
- `${CLINIC_GROUPS_COLLECTION}/${clinicGroupId}/usage_counters/${yearMonth}`
13035
- );
13036
- const counterSnap = await getDoc26(counterRef);
13037
- const currentCount = counterSnap.exists() ? ((_a = counterSnap.data()) == null ? void 0 : _a.appointmentsCreated) || 0 : 0;
13038
- if (currentCount + 1 > max) {
13039
- throw new TierLimitError("appointments this month", tier, currentCount, max);
13040
- }
13041
- }
13042
- async function enforceMessageLimit(db, clinicGroupId) {
13043
- var _a;
13044
- const tier = await getEffectiveTier(db, clinicGroupId);
13045
- const config = TIER_CONFIG[tier];
13046
- if (!config) return;
13047
- const max = config.limits.maxMessagesPerMonth;
13048
- if (max === -1) return;
13049
- const now = /* @__PURE__ */ new Date();
13050
- const yearMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
13051
- const counterRef = doc24(
13052
- db,
13053
- `${CLINIC_GROUPS_COLLECTION}/${clinicGroupId}/usage_counters/${yearMonth}`
13054
- );
13055
- const counterSnap = await getDoc26(counterRef);
13056
- const currentCount = counterSnap.exists() ? ((_a = counterSnap.data()) == null ? void 0 : _a.messagesCount) || 0 : 0;
13057
- if (currentCount + 1 > max) {
13058
- throw new TierLimitError("messages this month", tier, currentCount, max);
13012
+ if (currentCount + 1 > effectiveMax) {
13013
+ throw new TierLimitError("clinic branches", tier, currentCount, effectiveMax);
13059
13014
  }
13060
13015
  }
13061
13016
 
@@ -13311,7 +13266,7 @@ var PractitionerService = class extends BaseService {
13311
13266
  if (clinicSnap.exists()) {
13312
13267
  const clinicGroupId = clinicSnap.data().clinicGroupId;
13313
13268
  if (clinicGroupId) {
13314
- await enforceProviderLimit(this.db, clinicGroupId);
13269
+ await enforceProviderLimit(this.db, clinicGroupId, validData.clinics[0]);
13315
13270
  }
13316
13271
  }
13317
13272
  }
@@ -13391,7 +13346,7 @@ var PractitionerService = class extends BaseService {
13391
13346
  throw new Error(`Clinic ${clinicId} not found`);
13392
13347
  }
13393
13348
  if (clinic.clinicGroupId) {
13394
- await enforceProviderLimit(this.db, clinic.clinicGroupId);
13349
+ await enforceProviderLimit(this.db, clinic.clinicGroupId, clinicId);
13395
13350
  }
13396
13351
  const clinicsToAdd = /* @__PURE__ */ new Set([clinicId]);
13397
13352
  if (data.clinics && data.clinics.length > 0) {
@@ -23396,7 +23351,7 @@ var ProcedureService = class extends BaseService {
23396
23351
  throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
23397
23352
  }
23398
23353
  const clinic = clinicSnapshot.data();
23399
- await enforceProcedureLimit(this.db, clinic.clinicGroupId);
23354
+ await enforceProcedureLimit(this.db, clinic.clinicGroupId, validatedData.clinicBranchId, validatedData.practitionerId);
23400
23355
  const practitionerRef = doc44(this.db, PRACTITIONERS_COLLECTION, validatedData.practitionerId);
23401
23356
  const practitionerSnapshot = await getDoc45(practitionerRef);
23402
23357
  if (!practitionerSnapshot.exists()) {
@@ -23803,7 +23758,9 @@ var ProcedureService = class extends BaseService {
23803
23758
  throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
23804
23759
  }
23805
23760
  const clinic = clinicSnapshot.data();
23806
- await enforceProcedureLimit(this.db, clinic.clinicGroupId, practitionerIds.length);
23761
+ for (const practitionerId of practitionerIds) {
23762
+ await enforceProcedureLimit(this.db, clinic.clinicGroupId, validatedData.clinicBranchId, practitionerId);
23763
+ }
23807
23764
  let processedPhotos = [];
23808
23765
  if (validatedData.photos && validatedData.photos.length > 0) {
23809
23766
  const batchId = this.generateId();
@@ -28368,9 +28325,7 @@ export {
28368
28325
  USER_FORMS_SUBCOLLECTION,
28369
28326
  UserRole,
28370
28327
  UserService,
28371
- enforceAppointmentLimit,
28372
28328
  enforceBranchLimit,
28373
- enforceMessageLimit,
28374
28329
  enforceProcedureLimit,
28375
28330
  enforceProviderLimit,
28376
28331
  getEffectiveTier,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@blackcode_sa/metaestetics-api",
3
3
  "private": false,
4
- "version": "1.15.13",
4
+ "version": "1.15.14",
5
5
  "description": "Firebase authentication service with anonymous upgrade support",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",