fix merge conflicts

This commit is contained in:
olivermrbl
2021-02-27 10:15:42 +01:00
49 changed files with 1212 additions and 133 deletions
+41
View File
@@ -3,6 +3,47 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.11](https://github.com/medusajs/medusa/compare/@medusajs/medusa@1.1.10...@medusajs/medusa@1.1.11) (2021-02-25)
### Bug Fixes
* **medusa:** Add querying func. on customer retrievals ([#181](https://github.com/medusajs/medusa/issues/181)) ([22be418](https://github.com/medusajs/medusa/commit/22be418ec132944afe469106ba4b3b92f634d240))
## [1.1.10](https://github.com/medusajs/medusa/compare/@medusajs/medusa@1.1.10-next.1...@medusajs/medusa@1.1.10) (2021-02-25)
**Note:** Version bump only for package @medusajs/medusa
## [1.1.10-next.1](https://github.com/medusajs/medusa/compare/@medusajs/medusa@1.1.10-next.0...@medusajs/medusa@1.1.10-next.1) (2021-02-25)
### Bug Fixes
* update-product ([0320788](https://github.com/medusajs/medusa/commit/0320788aacf93da8a8951c6a540656da1772dba4))
## [1.1.10-next.0](https://github.com/medusajs/medusa/compare/@medusajs/medusa@1.1.9...@medusajs/medusa@1.1.10-next.0) (2021-02-22)
### Features
* **medusa:** tracking links ([#177](https://github.com/medusajs/medusa/issues/177)) ([99ad43b](https://github.com/medusajs/medusa/commit/99ad43bf47c3922f391d433448b1c4affd88f457))
## [1.1.9](https://github.com/medusajs/medusa/compare/@medusajs/medusa@1.1.8...@medusajs/medusa@1.1.9) (2021-02-18)
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@medusajs/medusa",
"version": "1.1.9",
"version": "1.1.11",
"description": "E-commerce for JAMstack",
"main": "dist/index.js",
"repository": {
@@ -2,18 +2,32 @@ export default async (req, res) => {
try {
const customerService = req.scope.resolve("customerService")
const limit = parseInt(req.query.limit) || 10
const limit = parseInt(req.query.limit) || 50
const offset = parseInt(req.query.offset) || 0
const selector = {}
if ("q" in req.query) {
selector.q = req.query.q
}
let expandFields = []
if ("expand" in req.query) {
expandFields = req.query.expand.split(",")
}
const listConfig = {
relations: [],
relations: expandFields.length ? expandFields : [],
skip: offset,
take: limit,
}
const customers = await customerService.list({}, listConfig)
const [customers, count] = await customerService.listAndCount(
selector,
listConfig
)
res.json({ customers, count: customers.length, offset, limit })
res.json({ customers, count, offset, limit })
} catch (error) {
throw error
}
@@ -10,6 +10,8 @@ const defaultRelations = [
"shipping_methods",
"payments",
"fulfillments",
"fulfillments.tracking_links",
"fulfillments.items",
"returns",
"gift_cards",
"gift_card_transactions",
@@ -23,7 +23,7 @@ export default async (req, res) => {
await claimService.createShipment(
claim_id,
value.fulfillment_id,
value.tracking_numbers
value.tracking_numbers.map(n => ({ tracking_number: n }))
)
const order = await orderService.retrieve(id, {
@@ -22,7 +22,7 @@ export default async (req, res) => {
await orderService.createShipment(
id,
value.fulfillment_id,
value.tracking_numbers
value.tracking_numbers.map(n => ({ tracking_number: n }))
)
const order = await orderService.retrieve(id, {
@@ -23,7 +23,7 @@ export default async (req, res) => {
await swapService.createShipment(
swap_id,
value.fulfillment_id,
value.tracking_numbers
value.tracking_numbers.map(n => ({ tracking_number: n }))
)
const order = await orderService.retrieve(id, {
@@ -188,6 +188,8 @@ export const defaultRelations = [
"shipping_methods",
"payments",
"fulfillments",
"fulfillments.tracking_links",
"fulfillments.items",
"returns",
"gift_cards",
"gift_card_transactions",
@@ -271,6 +273,7 @@ export const allowedRelations = [
"shipping_methods",
"payments",
"fulfillments",
"fulfillments.tracking_links",
"returns",
"claims",
"swaps",
@@ -14,13 +14,23 @@ export default async (req, res) => {
selector.q = req.query.q
}
let includeFields = []
if ("fields" in req.query) {
includeFields = req.query.fields.split(",")
}
let expandFields = []
if ("expand" in req.query) {
expandFields = req.query.expand.split(",")
}
if ("is_giftcard" in req.query) {
selector.is_giftcard = req.query.is_giftcard === "true"
}
const listConfig = {
select: defaultFields,
relations: defaultRelations,
select: includeFields.length ? includeFields : defaultFields,
relations: expandFields.length ? expandFields : defaultRelations,
skip: offset,
take: limit,
}
@@ -6,6 +6,9 @@ export default async (req, res) => {
const schema = Validator.object().keys({
title: Validator.string().optional(),
subtitle: Validator.string()
.optional()
.allow(null, ""),
description: Validator.string().optional(),
type: Validator.object()
.keys({
@@ -0,0 +1,16 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class trackingLinks1613656135167 implements MigrationInterface {
name = 'trackingLinks1613656135167'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "tracking_link" ("id" character varying NOT NULL, "url" character varying, "tracking_number" character varying NOT NULL, "fulfillment_id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deleted_at" TIMESTAMP WITH TIME ZONE, "metadata" jsonb, "idempotency_key" character varying, CONSTRAINT "PK_fcfd77feb9012ec2126d7c0bfb6" PRIMARY KEY ("id"))`);
await queryRunner.query(`ALTER TABLE "tracking_link" ADD CONSTRAINT "FK_471e9e4c96e02ba209a307db32b" FOREIGN KEY ("fulfillment_id") REFERENCES "fulfillment"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "tracking_link" DROP CONSTRAINT "FK_471e9e4c96e02ba209a307db32b"`);
await queryRunner.query(`DROP TABLE "tracking_link"`);
}
}
@@ -22,6 +22,7 @@ import { FulfillmentProvider } from "./fulfillment-provider"
import { FulfillmentItem } from "./fulfillment-item"
import { Swap } from "./swap"
import { ClaimOrder } from "./claim-order"
import { TrackingLink } from "./tracking-link"
@Entity()
export class Fulfillment {
@@ -76,6 +77,13 @@ export class Fulfillment {
)
items: FulfillmentItem[]
@OneToMany(
() => TrackingLink,
tl => tl.fulfillment,
{ cascade: ["insert"] }
)
tracking_links: TrackingLink[]
@Column({ type: "jsonb", default: [] })
tracking_numbers: string[]
@@ -0,0 +1,63 @@
import {
Entity,
Index,
BeforeInsert,
Column,
DeleteDateColumn,
CreateDateColumn,
UpdateDateColumn,
PrimaryColumn,
OneToOne,
OneToMany,
ManyToOne,
ManyToMany,
JoinColumn,
JoinTable,
} from "typeorm"
import { ulid } from "ulid"
import { Fulfillment } from "./fulfillment"
@Entity()
export class TrackingLink {
@PrimaryColumn()
id: string
@Column({ nullable: true })
url: string
@Column()
tracking_number: string
@Column()
fulfillment_id: string
@ManyToOne(
() => Fulfillment,
ful => ful.tracking_links
)
@JoinColumn({ name: "fulfillment_id" })
fulfillment: Fulfillment
@CreateDateColumn({ type: "timestamptz" })
created_at: Date
@UpdateDateColumn({ type: "timestamptz" })
updated_at: Date
@DeleteDateColumn({ type: "timestamptz" })
deleted_at: Date
@Column({ type: "jsonb", nullable: true })
metadata: any
@Column({ nullable: true })
idempotency_key: string
@BeforeInsert()
private beforeInsert() {
if (this.id) return
const id = ulid()
this.id = `tlink_${id}`
}
}
+50 -2
View File
@@ -1,5 +1,53 @@
import { EntityRepository, Repository } from "typeorm"
import { flatten, groupBy, map, merge } from "lodash"
import { EntityRepository, FindManyOptions, Repository } from "typeorm"
import { Product } from "../models/product"
@EntityRepository(Product)
export class ProductRepository extends Repository<Product> {}
export class ProductRepository extends Repository<Product> {
public async findWithRelations(
relations: Array<keyof Product> = [],
optionsWithoutRelations: Omit<FindManyOptions<Product>, "relations"> = {}
): Promise<Product[]> {
const entities = await this.find(optionsWithoutRelations)
const entitiesIds = entities.map(({ id }) => id)
const groupedRelations = {}
for (const rel of relations) {
const [topLevel] = rel.split(".")
if (groupedRelations[topLevel]) {
groupedRelations[topLevel].push(rel)
} else {
groupedRelations[topLevel] = [rel]
}
}
const entitiesIdsWithRelations = await Promise.all(
Object.entries(groupedRelations).map(([_, rels]) => {
return this.findByIds(entitiesIds, {
select: ["id"],
relations: rels as string[],
})
})
).then(flatten)
const entitiesAndRelations = entitiesIdsWithRelations.concat(entities)
const entitiesAndRelationsById = groupBy(entitiesAndRelations, "id")
return map(entitiesAndRelationsById, entityAndRelations =>
merge({}, ...entityAndRelations)
)
}
public async findOneWithRelations(
relations: Array<keyof Product> = [],
optionsWithoutRelations: Omit<FindManyOptions<Product>, "relations"> = {}
): Promise<Product> {
// Limit 1
optionsWithoutRelations.take = 1
const result = await this.findWithRelations(
relations,
optionsWithoutRelations
)
return result[0]
}
}
@@ -0,0 +1,5 @@
import { EntityRepository, Repository } from "typeorm"
import { TrackingLink } from "../models/tracking-link"
@EntityRepository(TrackingLink)
export class TrackingLinkRepository extends Repository<TrackingLink> {}
@@ -95,6 +95,7 @@ describe("FulfillmentService", () => {
})
describe("createShipment", () => {
const trackingLinkRepository = MockRepository({ create: c => c })
const fulfillmentRepository = MockRepository({
findOne: () => Promise.resolve({ id: IdMap.getId("fulfillment") }),
})
@@ -102,6 +103,7 @@ describe("FulfillmentService", () => {
const fulfillmentService = new FulfillmentService({
manager: MockManager,
fulfillmentRepository,
trackingLinkRepository,
})
const now = new Date()
@@ -113,14 +115,17 @@ describe("FulfillmentService", () => {
it("calls order model functions", async () => {
await fulfillmentService.createShipment(
IdMap.getId("fulfillment"),
["1234", "2345"],
[{ tracking_number: "1234" }, { tracking_number: "2345" }],
{}
)
expect(fulfillmentRepository.save).toHaveBeenCalledTimes(1)
expect(fulfillmentRepository.save).toHaveBeenCalledWith({
id: IdMap.getId("fulfillment"),
tracking_numbers: ["1234", "2345"],
tracking_links: [
{ tracking_number: "1234" },
{ tracking_number: "2345" },
],
metadata: {},
shipped_at: now,
})
@@ -1182,14 +1182,14 @@ describe("OrderService", () => {
await orderService.createShipment(
IdMap.getId("test"),
IdMap.getId("fulfillment"),
["1234", "2345"],
[{ tracking_number: "1234" }, { tracking_number: "2345" }],
{}
)
expect(fulfillmentService.createShipment).toHaveBeenCalledTimes(1)
expect(fulfillmentService.createShipment).toHaveBeenCalledWith(
IdMap.getId("fulfillment"),
["1234", "2345"],
[{ tracking_number: "1234" }, { tracking_number: "2345" }],
{}
)
@@ -11,7 +11,8 @@ const eventBusService = {
describe("ProductService", () => {
describe("retrieve", () => {
const productRepo = MockRepository({
findOne: () => Promise.resolve({ id: IdMap.getId("ironman") }),
findOneWithRelations: () =>
Promise.resolve({ id: IdMap.getId("ironman") }),
})
const productService = new ProductService({
manager: MockManager,
@@ -25,8 +26,8 @@ describe("ProductService", () => {
it("successfully retrieves a product", async () => {
const result = await productService.retrieve(IdMap.getId("ironman"))
expect(productRepo.findOne).toHaveBeenCalledTimes(1)
expect(productRepo.findOne).toHaveBeenCalledWith({
expect(productRepo.findOneWithRelations).toHaveBeenCalledTimes(1)
expect(productRepo.findOneWithRelations).toHaveBeenCalledWith(undefined, {
where: { id: IdMap.getId("ironman") },
})
@@ -42,7 +43,7 @@ describe("ProductService", () => {
options: [],
collection: { id: IdMap.getId("cat"), title: "Suits" },
}),
findOne: () => ({
findOneWithRelations: () => ({
id: IdMap.getId("ironman"),
title: "Suit",
options: [],
@@ -137,7 +138,7 @@ describe("ProductService", () => {
describe("update", () => {
const productRepository = MockRepository({
findOne: query => {
findOneWithRelations: (rels, query) => {
if (query.where.id === IdMap.getId("ironman&co")) {
return Promise.resolve({
id: IdMap.getId("ironman&co"),
@@ -322,7 +323,7 @@ describe("ProductService", () => {
describe("addOption", () => {
const productRepository = MockRepository({
findOne: query =>
findOneWithRelations: query =>
Promise.resolve({
id: IdMap.getId("ironman"),
options: [{ title: "Color" }],
@@ -395,7 +396,7 @@ describe("ProductService", () => {
describe("reorderVariants", () => {
const productRepository = MockRepository({
findOne: query =>
findOneWithRelations: query =>
Promise.resolve({
id: IdMap.getId("ironman"),
variants: [{ id: IdMap.getId("green") }, { id: IdMap.getId("blue") }],
@@ -453,7 +454,7 @@ describe("ProductService", () => {
describe("reorderOptions", () => {
const productRepository = MockRepository({
findOne: query =>
findOneWithRelations: query =>
Promise.resolve({
id: IdMap.getId("ironman"),
options: [
@@ -519,7 +520,7 @@ describe("ProductService", () => {
describe("updateOption", () => {
const productRepository = MockRepository({
findOne: query =>
findOneWithRelations: query =>
Promise.resolve({
id: IdMap.getId("ironman"),
options: [
@@ -594,7 +595,7 @@ describe("ProductService", () => {
describe("deleteOption", () => {
const productRepository = MockRepository({
findOne: query =>
findOneWithRelations: query =>
Promise.resolve({
id: IdMap.getId("ironman"),
variants: [
+2 -2
View File
@@ -418,7 +418,7 @@ class ClaimService extends BaseService {
})
}
async createShipment(id, fulfillmentId, trackingNumbers, metadata = []) {
async createShipment(id, fulfillmentId, trackingLinks, metadata = []) {
return this.atomicPhase_(async manager => {
const claim = await this.retrieve(id, {
relations: ["additional_items"],
@@ -426,7 +426,7 @@ class ClaimService extends BaseService {
const shipment = await this.fulfillmentService_
.withTransaction(manager)
.createShipment(fulfillmentId, trackingNumbers, metadata)
.createShipment(fulfillmentId, trackingLinks, metadata)
claim.fulfillment_status = "shipped"
+45
View File
@@ -3,6 +3,7 @@ import Scrypt from "scrypt-kdf"
import _ from "lodash"
import { Validator, MedusaError } from "medusa-core-utils"
import { BaseService } from "medusa-interfaces"
import { Brackets } from "typeorm"
/**
* Provides layer to manipulate customers.
@@ -132,6 +133,50 @@ class CustomerService extends BaseService {
return customerRepo.find(query)
}
async listAndCount(
selector,
config = { relations: [], skip: 0, take: 50, order: { created_at: "DESC" } }
) {
const customerRepo = this.manager_.getCustomRepository(
this.customerRepository_
)
let q
if ("q" in selector) {
q = selector.q
delete selector.q
}
const query = this.buildQuery_(selector, config)
if (q) {
const where = query.where
delete where.email
delete where.first_name
delete where.last_name
query.join = {
alias: "customer",
}
query.where = qb => {
qb.where(where)
qb.andWhere(
new Brackets(qb => {
qb.where(`customer.first_name ILIKE :q`, { q: `%${q}%` })
.orWhere(`customer.last_name ILIKE :q`, { q: `%${q}%` })
.orWhere(`customer.email ILIKE :q`, { q: `%${q}%` })
})
)
}
}
const [customers, count] = await customerRepo.findAndCount(query)
return [customers, count]
}
/**
* Return the total number of documents in database
* @return {Promise} the result of the count operation
+15 -3
View File
@@ -11,6 +11,7 @@ class FulfillmentService extends BaseService {
manager,
totalsService,
fulfillmentRepository,
trackingLinkRepository,
shippingProfileService,
lineItemService,
fulfillmentProviderService,
@@ -26,6 +27,9 @@ class FulfillmentService extends BaseService {
/** @private @const {FulfillmentRepository} */
this.fulfillmentRepository_ = fulfillmentRepository
/** @private @const {TrackingLinkRepository} */
this.trackingLinkRepository_ = trackingLinkRepository
/** @private @const {ShippingProfileService} */
this.shippingProfileService_ = shippingProfileService
@@ -44,6 +48,7 @@ class FulfillmentService extends BaseService {
const cloned = new FulfillmentService({
manager: transactionManager,
totalsService: this.totalsService_,
trackingLinkRepository: this.trackingLinkRepository_,
fulfillmentRepository: this.fulfillmentRepository_,
shippingProfileService: this.shippingProfileService_,
lineItemService: this.lineItemService_,
@@ -235,15 +240,18 @@ class FulfillmentService extends BaseService {
* Creates a shipment by marking a fulfillment as shipped. Adds
* tracking numbers and potentially more metadata.
* @param {Order} fulfillmentId - the fulfillment to ship
* @param {string[]} trackingNumbers - tracking numbers for the shipment
* @param {TrackingLink[]} trackingNumbers - tracking numbers for the shipment
* @param {object} metadata - potential metadata to add
* @return {Fulfillment} the shipped fulfillment
*/
async createShipment(fulfillmentId, trackingNumbers, metadata) {
async createShipment(fulfillmentId, trackingLinks, metadata) {
return this.atomicPhase_(async manager => {
const fulfillmentRepository = manager.getCustomRepository(
this.fulfillmentRepository_
)
const trackingLinkRepo = manager.getCustomRepository(
this.trackingLinkRepository_
)
const fulfillment = await this.retrieve(fulfillmentId, {
relations: ["items"],
@@ -251,7 +259,11 @@ class FulfillmentService extends BaseService {
const now = new Date()
fulfillment.shipped_at = now
fulfillment.tracking_numbers = trackingNumbers
fulfillment.tracking_links = trackingLinks.map(tl =>
trackingLinkRepo.create(tl)
)
fulfillment.metadata = {
...fulfillment.metadata,
...metadata,
+3 -3
View File
@@ -553,13 +553,13 @@ class OrderService extends BaseService {
* have been created in regards to the shipment.
* @param {string} orderId - the id of the order that has been shipped
* @param {string} fulfillmentId - the fulfillment that has now been shipped
* @param {Array<String>} trackingNumbers - array of tracking numebers
* @param {TrackingLink[]} trackingLinks - array of tracking numebers
* associated with the shipment
* @param {Dictionary<String, String>} metadata - optional metadata to add to
* the fulfillment
* @return {order} the resulting order following the update.
*/
async createShipment(orderId, fulfillmentId, trackingNumbers, metadata = {}) {
async createShipment(orderId, fulfillmentId, trackingLinks, metadata = {}) {
return this.atomicPhase_(async manager => {
const order = await this.retrieve(orderId, { relations: ["items"] })
const shipment = await this.fulfillmentService_.retrieve(fulfillmentId)
@@ -573,7 +573,7 @@ class OrderService extends BaseService {
const shipmentRes = await this.fulfillmentService_
.withTransaction(manager)
.createShipment(fulfillmentId, trackingNumbers, metadata)
.createShipment(fulfillmentId, trackingLinks, metadata)
order.fulfillment_status = "shipped"
for (const item of order.items) {
+27 -3
View File
@@ -93,6 +93,17 @@ class ProductService extends BaseService {
const query = this.buildQuery_(selector, config)
if (config.relations && config.relations.length > 0) {
query.relations = config.relations
}
if (config.select && config.select.length > 0) {
query.select = config.select
}
const rels = query.relations
delete query.relations
if (q) {
const where = query.where
@@ -122,7 +133,7 @@ class ProductService extends BaseService {
}
}
return productRepo.find(query)
return productRepo.findWithRelations(rels, query)
}
/**
@@ -147,8 +158,21 @@ class ProductService extends BaseService {
this.productRepository_
)
const validatedId = this.validateId_(productId)
const query = this.buildQuery_({ id: validatedId }, config)
const product = await productRepo.findOne(query)
const query = { where: { id: validatedId } }
if (config.relations && config.relations.length > 0) {
query.relations = config.relations
}
if (config.select && config.select.length > 0) {
query.select = config.select
}
const rels = query.relations
delete query.relations
const product = await productRepo.findOneWithRelations(rels, query)
if (!product) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
+3 -3
View File
@@ -671,12 +671,12 @@ class SwapService extends BaseService {
* @param {string} swapId - the id of the swap that has been shipped.
* @param {string} fulfillmentId - the id of the specific fulfillment that
* has been shipped
* @param {Array<string>} trackingNumbers - the tracking numbers associated
* @param {TrackingLink[]} trackingLinks - the tracking numbers associated
* with the shipment
* @param {object} metadata - optional metadata to attach to the shipment.
* @returns {Promise<Swap>} the updated swap with new fulfillments and status.
*/
async createShipment(swapId, fulfillmentId, trackingNumbers, metadata = {}) {
async createShipment(swapId, fulfillmentId, trackingLinks, metadata = {}) {
return this.atomicPhase_(async manager => {
const swap = await this.retrieve(swapId, {
relations: ["additional_items"],
@@ -685,7 +685,7 @@ class SwapService extends BaseService {
// Update the fulfillment to register
const shipment = await this.fulfillmentService_
.withTransaction(manager)
.createShipment(fulfillmentId, trackingNumbers, metadata)
.createShipment(fulfillmentId, trackingLinks, metadata)
swap.fulfillment_status = "shipped"