Skip to content

Commit

Permalink
feat(server): Implement CustomerGroup entity
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbromley committed Oct 12, 2018
1 parent 5ea09ef commit ff495fc
Show file tree
Hide file tree
Showing 12 changed files with 321 additions and 4 deletions.
2 changes: 1 addition & 1 deletion schema.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions server/mock-data/mock-data.service.ts
Expand Up @@ -203,9 +203,9 @@ export class MockDataService {
password: 'test',
};

const customer: Customer | void = await this.client
const customer: { id: string; emailAddress: string } | void = await this.client
.query(query1, variables1)
.then((data: any) => data.createCustomer as Customer, err => this.log(err));
.then((data: any) => data.createCustomer, err => this.log(err));

if (customer) {
const query2 = gql`
Expand Down
2 changes: 2 additions & 0 deletions server/src/api/api.module.ts
Expand Up @@ -19,6 +19,7 @@ import { AuthResolver } from './resolvers/auth.resolver';
import { ChannelResolver } from './resolvers/channel.resolver';
import { ConfigResolver } from './resolvers/config.resolver';
import { CountryResolver } from './resolvers/country.resolver';
import { CustomerGroupResolver } from './resolvers/customer-group.resolver';
import { CustomerResolver } from './resolvers/customer.resolver';
import { FacetResolver } from './resolvers/facet.resolver';
import { OrderResolver } from './resolvers/order.resolver';
Expand All @@ -37,6 +38,7 @@ const exportedProviders = [
CountryResolver,
FacetResolver,
CustomerResolver,
CustomerGroupResolver,
OrderResolver,
ProductOptionResolver,
ProductResolver,
Expand Down
65 changes: 65 additions & 0 deletions server/src/api/resolvers/customer-group.resolver.ts
@@ -0,0 +1,65 @@
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import {
AddCustomersToGroupMutationArgs,
CreateCustomerGroupMutationArgs,
CustomerGroupQueryArgs,
Permission,
RemoveCustomersFromGroupMutationArgs,
UpdateCustomerGroupMutationArgs,
} from 'shared/generated-types';

import { CustomerGroup } from '../../entity/customer-group/customer-group.entity';
import { CustomerGroupService } from '../../service/providers/customer-group.service';
import { Allow } from '../common/auth-guard';
import { Decode } from '../common/id-interceptor';
import { RequestContext } from '../common/request-context';
import { Ctx } from '../common/request-context.decorator';

@Resolver('CustomerGroup')
export class CustomerGroupResolver {
constructor(private customerGroupService: CustomerGroupService) {}

@Query()
@Allow(Permission.ReadCustomer)
customerGroups(@Ctx() ctx: RequestContext): Promise<CustomerGroup[]> {
return this.customerGroupService.findAll();
}

@Query()
@Allow(Permission.ReadCustomer)
async customerGroup(
@Ctx() ctx: RequestContext,
@Args() args: CustomerGroupQueryArgs,
): Promise<CustomerGroup | undefined> {
return this.customerGroupService.findOne(args.id);
}

@Mutation()
@Allow(Permission.CreateCustomer)
@Decode('customerIds')
async createCustomerGroup(@Args() args: CreateCustomerGroupMutationArgs): Promise<CustomerGroup> {
return this.customerGroupService.create(args.input);
}

@Mutation()
@Allow(Permission.UpdateCustomer)
async updateCustomerGroup(@Args() args: UpdateCustomerGroupMutationArgs): Promise<CustomerGroup> {
return this.customerGroupService.update(args.input);
}

@Mutation()
@Allow(Permission.UpdateCustomer)
@Decode('customerGroupId', 'customerIds')
async addCustomersToGroup(@Args() args: AddCustomersToGroupMutationArgs): Promise<CustomerGroup> {
return this.customerGroupService.addCustomersToGroup(args);
}

@Mutation()
@Allow(Permission.UpdateCustomer)
@Decode('customerGroupId', 'customerIds')
async removeCustomersFromGroup(
@Args() args: RemoveCustomersFromGroupMutationArgs,
): Promise<CustomerGroup> {
return this.customerGroupService.removeCustomersFromGroup(args);
}
}
15 changes: 15 additions & 0 deletions server/src/api/types/customer-group.api.graphql
@@ -0,0 +1,15 @@
type Query {
customerGroups: [CustomerGroup!]!
customerGroup(id: ID!): CustomerGroup
}

type Mutation {
"Create a new CustomerGroup"
createCustomerGroup(input: CreateCustomerGroupInput!): CustomerGroup!
"Update an existing CustomerGroup"
updateCustomerGroup(input: UpdateCustomerGroupInput!): CustomerGroup!
"Add Customers to a CustomerGroup"
addCustomersToGroup(customerGroupId: ID!, customerIds: [ID!]!): CustomerGroup!
"Remove Customers from a CustomerGroup"
removeCustomersFromGroup(customerGroupId: ID!, customerIds: [ID!]!): CustomerGroup!
}
17 changes: 17 additions & 0 deletions server/src/entity/customer-group/customer-group.entity.ts
@@ -0,0 +1,17 @@
import { DeepPartial } from 'shared/shared-types';
import { Column, Entity, ManyToMany } from 'typeorm';

import { VendureEntity } from '../base/base.entity';
import { Customer } from '../customer/customer.entity';

@Entity()
export class CustomerGroup extends VendureEntity {
constructor(input?: DeepPartial<CustomerGroup>) {
super(input);
}

@Column() name: string;

@ManyToMany(type => Customer)
customers: Customer[];
}
16 changes: 16 additions & 0 deletions server/src/entity/customer-group/customer-group.graphql
@@ -0,0 +1,16 @@
type CustomerGroup implements Node {
id: ID!
createdAt: DateTime!
updatedAt: DateTime!
name: String!
}

input CreateCustomerGroupInput {
name: String!
customerIds: [ID!]
}

input UpdateCustomerGroupInput {
id: ID!
name: String
}
7 changes: 6 additions & 1 deletion server/src/entity/customer/customer.entity.ts
@@ -1,10 +1,11 @@
import { DeepPartial } from 'shared/shared-types';
import { HasCustomFields } from 'shared/shared-types';
import { Column, Entity, JoinColumn, OneToMany, OneToOne } from 'typeorm';
import { Column, Entity, JoinColumn, JoinTable, ManyToMany, OneToMany, OneToOne } from 'typeorm';

import { Address } from '../address/address.entity';
import { VendureEntity } from '../base/base.entity';
import { CustomCustomerFields } from '../custom-entity-fields';
import { CustomerGroup } from '../customer-group/customer-group.entity';
import { Order } from '../order/order.entity';
import { User } from '../user/user.entity';

Expand All @@ -24,6 +25,10 @@ export class Customer extends VendureEntity implements HasCustomFields {
@Column({ unique: true })
emailAddress: string;

@ManyToMany(type => CustomerGroup)
@JoinTable()
groups: CustomerGroup[];

@OneToMany(type => Address, address => address.customer)
addresses: Address[];

Expand Down
2 changes: 2 additions & 0 deletions server/src/entity/entities.ts
Expand Up @@ -4,6 +4,7 @@ import { Administrator } from './administrator/administrator.entity';
import { Asset } from './asset/asset.entity';
import { Channel } from './channel/channel.entity';
import { Country } from './country/country.entity';
import { CustomerGroup } from './customer-group/customer-group.entity';
import { Customer } from './customer/customer.entity';
import { FacetValueTranslation } from './facet-value/facet-value-translation.entity';
import { FacetValue } from './facet-value/facet-value.entity';
Expand Down Expand Up @@ -40,6 +41,7 @@ export const coreEntitiesMap = {
Channel,
Country,
Customer,
CustomerGroup,
Facet,
FacetTranslation,
FacetValue,
Expand Down
76 changes: 76 additions & 0 deletions server/src/service/providers/customer-group.service.ts
@@ -0,0 +1,76 @@
import { Injectable } from '@nestjs/common';
import { InjectConnection } from '@nestjs/typeorm';
import {
AddCustomersToGroupMutationArgs,
CreateCustomerGroupInput,
RemoveCustomersFromGroupMutationArgs,
UpdateCustomerGroupInput,
} from 'shared/generated-types';
import { ID } from 'shared/shared-types';
import { unique } from 'shared/unique';
import { Connection } from 'typeorm';

import { assertFound } from '../../common/utils';
import { CustomerGroup } from '../../entity/customer-group/customer-group.entity';
import { Customer } from '../../entity/customer/customer.entity';
import { I18nError } from '../../i18n/i18n-error';
import { patchEntity } from '../helpers/patch-entity';

@Injectable()
export class CustomerGroupService {
constructor(@InjectConnection() private connection: Connection) {}

findAll(): Promise<CustomerGroup[]> {
return this.connection.getRepository(CustomerGroup).find({});
}

findOne(customerGroupId: ID): Promise<CustomerGroup | undefined> {
return this.connection.getRepository(CustomerGroup).findOne(customerGroupId);
}

async create(input: CreateCustomerGroupInput): Promise<CustomerGroup> {
const customerGroup = new CustomerGroup(input);
if (input.customerIds) {
customerGroup.customers = await this.getCustomersFromIds(input.customerIds);
}
const newCustomerGroup = await this.connection.getRepository(CustomerGroup).save(customerGroup);
return assertFound(this.findOne(newCustomerGroup.id));
}

async update(input: UpdateCustomerGroupInput): Promise<CustomerGroup> {
const customerGroup = await this.getCustomerGroupOrThrow(input.id);
const updatedCustomerGroup = patchEntity(customerGroup, input);
await this.connection.getRepository(CustomerGroup).save(updatedCustomerGroup);
return assertFound(this.findOne(customerGroup.id));
}

async addCustomersToGroup(input: AddCustomersToGroupMutationArgs): Promise<CustomerGroup> {
const countries = await this.getCustomersFromIds(input.customerIds);
const customerGroup = await this.getCustomerGroupOrThrow(input.customerGroupId);
const customers = unique(customerGroup.customers.concat(countries), 'id');
customerGroup.customers = customers;
await this.connection.getRepository(CustomerGroup).save(customerGroup);
return customerGroup;
}

async removeCustomersFromGroup(input: RemoveCustomersFromGroupMutationArgs): Promise<CustomerGroup> {
const customerGroup = await this.getCustomerGroupOrThrow(input.customerGroupId);
customerGroup.customers = customerGroup.customers.filter(
customer => !input.customerIds.includes(customer.id as string),
);
await this.connection.getRepository(CustomerGroup).save(customerGroup);
return customerGroup;
}

private async getCustomerGroupOrThrow(id: ID): Promise<CustomerGroup> {
const customerGroup = await this.findOne(id);
if (!customerGroup) {
throw new I18nError(`error.entity-with-id-not-found`, { entityName: 'CustomerGroup', id });
}
return customerGroup;
}

private getCustomersFromIds(ids: ID[]): Promise<Customer[]> {
return this.connection.getRepository(Customer).findByIds(ids);
}
}
2 changes: 2 additions & 0 deletions server/src/service/service.module.ts
Expand Up @@ -12,6 +12,7 @@ import { AssetService } from './providers/asset.service';
import { AuthService } from './providers/auth.service';
import { ChannelService } from './providers/channel.service';
import { CountryService } from './providers/country.service';
import { CustomerGroupService } from './providers/customer-group.service';
import { CustomerService } from './providers/customer.service';
import { FacetValueService } from './providers/facet-value.service';
import { FacetService } from './providers/facet.service';
Expand All @@ -31,6 +32,7 @@ const exportedProviders = [
AuthService,
ChannelService,
CountryService,
CustomerGroupService,
CustomerService,
FacetService,
FacetValueService,
Expand Down

0 comments on commit ff495fc

Please sign in to comment.