@rsc-labs/medusa-store-analytics
Version:
Get analytics data about your store
313 lines (312 loc) • 13.8 kB
JavaScript
;
/*
* Copyright 2024 RSC-Labs, https://rsoftcon.com/
*
* MIT License
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
const medusa_1 = require("@medusajs/medusa");
const medusa_2 = require("@medusajs/medusa");
const dateTransformations_1 = require("./utils/dateTransformations");
const typeorm_1 = require("typeorm");
class OrdersAnalyticsService extends medusa_1.TransactionBaseService {
constructor(container) {
super(container);
this.orderService = container.orderService;
}
async getOrdersHistory(orderStatuses, from, to, dateRangeFromCompareTo, dateRangeToCompareTo) {
const orderStatusesAsStrings = Object.values(orderStatuses);
if (orderStatusesAsStrings.length) {
if (dateRangeFromCompareTo && from && to && dateRangeToCompareTo) {
const resolution = (0, dateTransformations_1.calculateResolution)(from);
const query = this.activeManager_.getRepository(medusa_2.Order)
.createQueryBuilder('order')
.select(`
CASE
WHEN order.created_at < :from AND order.created_at >= :dateRangeFromCompareTo THEN 'previous'
ELSE 'current'
END AS type,
date_trunc('${resolution}', order.created_at) AS date
`)
.setParameters({ from, dateRangeFromCompareTo })
.addSelect('COUNT(order.id)', 'orderCount')
.where(`created_at >= :dateRangeFromCompareTo`, { dateRangeFromCompareTo })
.andWhere(`status IN(:...orderStatusesAsStrings)`, { orderStatusesAsStrings });
const orders = await query
.groupBy('type, date')
.orderBy('date, type', 'ASC')
.getRawMany();
const finalOrders = orders.reduce((acc, entry) => {
const type = entry.type;
const date = entry.date;
const orderCount = entry.orderCount;
if (!acc[type]) {
acc[type] = [];
}
acc[type].push({ date, orderCount });
return acc;
}, {});
return {
dateRangeFrom: from.getTime(),
dateRangeTo: to.getTime(),
dateRangeFromCompareTo: dateRangeFromCompareTo.getTime(),
dateRangeToCompareTo: dateRangeToCompareTo.getTime(),
current: finalOrders.current ? finalOrders.current : [],
previous: finalOrders.previous ? finalOrders.previous : [],
};
}
let startQueryFrom;
if (!dateRangeFromCompareTo) {
if (from) {
startQueryFrom = from;
}
else {
// All time
const lastOrder = await this.activeManager_.getRepository(medusa_2.Order).find({
skip: 0,
take: 1,
order: { created_at: "ASC" },
where: { status: (0, typeorm_1.In)(orderStatusesAsStrings) }
});
if (lastOrder.length > 0) {
startQueryFrom = lastOrder[0].created_at;
}
}
}
else {
startQueryFrom = dateRangeFromCompareTo;
}
if (startQueryFrom) {
const resolution = (0, dateTransformations_1.calculateResolution)(startQueryFrom);
const query = this.activeManager_.getRepository(medusa_2.Order)
.createQueryBuilder('order')
.select(`date_trunc('${resolution}', order.created_at)`, 'date')
.addSelect('COUNT(order.id)', 'orderCount')
.where(`created_at >= :startQueryFrom`, { startQueryFrom })
.andWhere(`status IN(:...orderStatusesAsStrings)`, { orderStatusesAsStrings });
const orders = await query
.groupBy('date')
.orderBy('date', 'ASC')
.getRawMany();
return {
dateRangeFrom: startQueryFrom.getTime(),
dateRangeTo: to ? to.getTime() : new Date(Date.now()).getTime(),
dateRangeFromCompareTo: undefined,
dateRangeToCompareTo: undefined,
current: orders,
previous: []
};
}
}
return {
dateRangeFrom: undefined,
dateRangeTo: undefined,
dateRangeFromCompareTo: undefined,
dateRangeToCompareTo: undefined,
current: [],
previous: []
};
}
async getOrdersCount(orderStatuses, from, to, dateRangeFromCompareTo, dateRangeToCompareTo) {
let startQueryFrom;
const orderStatusesAsStrings = Object.values(orderStatuses);
if (orderStatusesAsStrings.length) {
if (!dateRangeFromCompareTo) {
if (from) {
startQueryFrom = from;
}
else {
// All time
const lastOrder = await this.activeManager_.getRepository(medusa_2.Order).find({
skip: 0,
take: 1,
order: { created_at: "ASC" },
where: { status: (0, typeorm_1.In)(orderStatusesAsStrings) }
});
if (lastOrder.length > 0) {
startQueryFrom = lastOrder[0].created_at;
}
}
}
else {
startQueryFrom = dateRangeFromCompareTo;
}
const orders = await this.orderService.listAndCount({
created_at: startQueryFrom ? { gte: startQueryFrom } : undefined,
status: (0, typeorm_1.In)(orderStatusesAsStrings)
}, {
select: [
"id",
"created_at",
"updated_at"
],
order: { created_at: "DESC" },
});
if (dateRangeFromCompareTo && from && to && dateRangeToCompareTo) {
const previousOrders = orders[0].filter(order => order.created_at < from);
const currentOrders = orders[0].filter(order => order.created_at >= from);
return {
dateRangeFrom: from.getTime(),
dateRangeTo: to.getTime(),
dateRangeFromCompareTo: dateRangeFromCompareTo.getTime(),
dateRangeToCompareTo: dateRangeToCompareTo.getTime(),
current: currentOrders.length,
previous: previousOrders.length
};
}
if (startQueryFrom) {
return {
dateRangeFrom: startQueryFrom.getTime(),
dateRangeTo: to ? to.getTime() : new Date(Date.now()).getTime(),
dateRangeFromCompareTo: undefined,
dateRangeToCompareTo: undefined,
current: orders[1],
previous: 0
};
}
}
return {
dateRangeFrom: undefined,
dateRangeTo: undefined,
dateRangeFromCompareTo: undefined,
dateRangeToCompareTo: undefined,
current: 0,
previous: 0
};
}
async getPaymentProviderPopularity(from, to, dateRangeFromCompareTo, dateRangeToCompareTo) {
function calculateSumAndPercentageOfResults(results) {
const orderMap = new Map();
let allSum = 0;
results.forEach(result => {
const { orderCount, paymentProviderId } = result;
if (orderMap.has(paymentProviderId)) {
const sum = parseInt(orderMap.get(paymentProviderId)) + parseInt(orderCount);
orderMap.set(paymentProviderId, sum.toFixed());
}
else {
orderMap.set(paymentProviderId, orderCount);
}
});
const newArray = [];
orderMap.forEach((value) => {
allSum += parseInt(value);
});
orderMap.forEach((value, key) => {
newArray.push({
orderCount: value,
percentage: (parseInt(value) * 100 / allSum).toFixed(2),
paymentProviderId: key
});
});
return newArray;
}
if (dateRangeFromCompareTo && from && to && dateRangeToCompareTo) {
const resolution = (0, dateTransformations_1.calculateResolution)(from);
const query = this.activeManager_
.getRepository(medusa_2.Order)
.createQueryBuilder('order')
.select(`
CASE
WHEN order.created_at < :from AND order.created_at >= :dateRangeFromCompareTo THEN 'previous'
ELSE 'current'
END AS type`)
.addSelect(`date_trunc('${resolution}', order.created_at)`, 'date')
.addSelect('COUNT(order.id)', 'orderCount')
.leftJoinAndSelect('order.payments', 'payments')
.where('order.created_at >= :dateRangeFromCompareTo', { dateRangeFromCompareTo });
const ordersCountWithPayments = await query
.groupBy('date, type, payments.id')
.orderBy('date', 'ASC')
.setParameters({ from, dateRangeFromCompareTo })
.getRawMany();
const finalOrders = ordersCountWithPayments.reduce((acc, entry) => {
const type = entry.type;
const orderCount = entry.orderCount;
const paymentProviderId = entry.payments_provider_id;
if (!acc[type]) {
acc[type] = [];
}
acc[type].push({
orderCount,
paymentProviderId,
});
return acc;
}, {});
const finalOrdersCurrentGrouped = calculateSumAndPercentageOfResults(finalOrders.current ? finalOrders.current : []);
const finalOrdersPreviousGrouped = calculateSumAndPercentageOfResults(finalOrders.previous ? finalOrders.previous : []);
return {
dateRangeFrom: from.getTime(),
dateRangeTo: to.getTime(),
dateRangeFromCompareTo: dateRangeFromCompareTo.getTime(),
dateRangeToCompareTo: dateRangeToCompareTo.getTime(),
current: finalOrdersCurrentGrouped ? finalOrdersCurrentGrouped : [],
previous: finalOrdersPreviousGrouped ? finalOrdersPreviousGrouped : [],
};
}
let startQueryFrom;
if (!dateRangeFromCompareTo) {
if (from) {
startQueryFrom = from;
}
else {
// All time
const lastOrder = await this.activeManager_.getRepository(medusa_2.Order).find({
skip: 0,
take: 1,
order: { created_at: "ASC" },
});
if (lastOrder.length > 0) {
startQueryFrom = lastOrder[0].created_at;
}
}
}
else {
startQueryFrom = dateRangeFromCompareTo;
}
if (startQueryFrom) {
const resolution = (0, dateTransformations_1.calculateResolution)(startQueryFrom);
const query = this.activeManager_
.getRepository(medusa_2.Order)
.createQueryBuilder('order')
.select(`date_trunc('${resolution}', order.created_at)`, 'date')
.addSelect('COUNT(order.id)', 'orderCount')
.leftJoinAndSelect('order.payments', 'payments')
.where('order.created_at >= :startQueryFrom', { startQueryFrom });
const ordersCountWithPayments = await query
.groupBy('date, payments.id')
.orderBy('date', 'ASC')
.getRawMany();
const initialOrders = ordersCountWithPayments.map(order => {
return {
orderCount: order.orderCount,
paymentProviderId: order.payments_provider_id,
};
});
const finalOrdersGrouped = calculateSumAndPercentageOfResults(initialOrders ? initialOrders : []);
return {
dateRangeFrom: startQueryFrom.getTime(),
dateRangeTo: to ? to.getTime() : new Date(Date.now()).getTime(),
dateRangeFromCompareTo: undefined,
dateRangeToCompareTo: undefined,
current: finalOrdersGrouped,
previous: []
};
}
return {
dateRangeFrom: undefined,
dateRangeTo: undefined,
dateRangeFromCompareTo: undefined,
dateRangeToCompareTo: undefined,
current: [],
previous: []
};
}
}
exports.default = OrdersAnalyticsService;