Skip to content

Commit

Permalink
Merge pull request #929 from AbleKSaju/feat-lead
Browse files Browse the repository at this point in the history
feat: lead
  • Loading branch information
akshayitzme authored Aug 19, 2024
2 parents 47f4f83 + 3e10ba6 commit 7205f5a
Show file tree
Hide file tree
Showing 17 changed files with 457 additions and 5 deletions.
10 changes: 10 additions & 0 deletions fyo/model/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,13 @@ export type DocStatus =
| 'NotSaved'
| 'Submitted'
| 'Cancelled';

export type LeadStatus =
| ''
| 'Open'
| 'Replied'
| 'Interested'
| 'Opportunity'
| 'Converted'
| 'Quotation'
| 'DonotContact'
4 changes: 4 additions & 0 deletions models/baseModels/AccountingSettings/AccountingSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export class AccountingSettings extends Doc {
enableDiscounting?: boolean;
enableInventory?: boolean;
enablePriceList?: boolean;
enableLead?: boolean;
enableFormCustomization?: boolean;
enableInvoiceReturns?: boolean;

Expand Down Expand Up @@ -48,6 +49,9 @@ export class AccountingSettings extends Doc {
enableInventory: () => {
return !!this.enableInventory;
},
enableLead: () => {
return !!this.enableLead;
},
enableInvoiceReturns: () => {
return !!this.enableInvoiceReturns;
},
Expand Down
4 changes: 4 additions & 0 deletions models/baseModels/Invoice/Invoice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ export abstract class Invoice extends Transactional {
async afterSubmit() {
await super.afterSubmit();

if (this.schemaName === ModelNameEnum.SalesQuote) {
return;
}

// update outstanding amounts
await this.fyo.db.update(this.schemaName, {
name: this.name as string,
Expand Down
51 changes: 51 additions & 0 deletions models/baseModels/Lead/Lead.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Fyo } from 'fyo';
import { Doc } from 'fyo/model/doc';
import {
Action,
LeadStatus,
ListViewSettings,
ValidationMap,
} from 'fyo/model/types';
import { getLeadActions, getLeadStatusColumn } from 'models/helpers';
import {
validateEmail,
validatePhoneNumber,
} from 'fyo/model/validationFunction';
import { ModelNameEnum } from 'models/types';

export class Lead extends Doc {
status?: LeadStatus;

validations: ValidationMap = {
email: validateEmail,
mobile: validatePhoneNumber,
};

createCustomer() {
return this.fyo.doc.getNewDoc(ModelNameEnum.Party, {
...this.getValidDict(),
fromLead: this.name,
phone: this.mobile as string,
role: 'Customer',
});
}

createSalesQuote() {
const data: { party: string | undefined; referenceType: string } = {
party: this.name,
referenceType: ModelNameEnum.Lead,
};

return this.fyo.doc.getNewDoc(ModelNameEnum.SalesQuote, data);
}

static getActions(fyo: Fyo): Action[] {
return getLeadActions(fyo);
}

static getListViewSettings(): ListViewSettings {
return {
columns: ['name', getLeadStatusColumn(), 'email', 'mobile'],
};
}
}
22 changes: 22 additions & 0 deletions models/baseModels/Party/Party.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ import {
} from 'fyo/model/validationFunction';
import { Money } from 'pesa';
import { PartyRole } from './types';
import { ModelNameEnum } from 'models/types';

export class Party extends Doc {
role?: PartyRole;
party?: string;
fromLead?: string;
defaultAccount?: string;
outstandingAmount?: Money;
async updateOutstandingAmount() {
Expand Down Expand Up @@ -125,6 +128,25 @@ export class Party extends Doc {
};
}

async afterDelete() {
await super.afterDelete();
if (!this.fromLead) {
return;
}
const leadData = await this.fyo.doc.getDoc(ModelNameEnum.Lead, this.name);
await leadData.setAndSync('status', 'Interested');
}

async afterSync() {
await super.afterSync();
if (!this.fromLead) {
return;
}

const leadData = await this.fyo.doc.getDoc(ModelNameEnum.Lead, this.name);
await leadData.setAndSync('status', 'Converted');
}

static getActions(fyo: Fyo): Action[] {
return [
{
Expand Down
24 changes: 23 additions & 1 deletion models/baseModels/SalesQuote/SalesQuote.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { Fyo } from 'fyo';
import { DocValueMap } from 'fyo/core/types';
import { Action, ListViewSettings } from 'fyo/model/types';
import { Action, FiltersMap, ListViewSettings } from 'fyo/model/types';
import { ModelNameEnum } from 'models/types';
import { getQuoteActions, getTransactionStatusColumn } from '../../helpers';
import { Invoice } from '../Invoice/Invoice';
import { SalesQuoteItem } from '../SalesQuoteItem/SalesQuoteItem';
import { Defaults } from '../Defaults/Defaults';
import { Doc } from 'fyo/model/doc';
import { Party } from '../Party/Party';

export class SalesQuote extends Invoice {
items?: SalesQuoteItem[];
party?: string;
name?: string;
referenceType?:
| ModelNameEnum.SalesInvoice
| ModelNameEnum.PurchaseInvoice
| ModelNameEnum.Lead;

// This is an inherited method and it must keep the async from the parent
// class
Expand Down Expand Up @@ -49,6 +57,20 @@ export class SalesQuote extends Invoice {
return invoice;
}

static filters: FiltersMap = {
numberSeries: (doc: Doc) => ({ referenceType: doc.schemaName }),
};

async afterSubmit(): Promise<void> {
await super.afterSubmit();

if (this.referenceType == ModelNameEnum.Lead) {
const partyDoc = (await this.loadAndGetLink('party')) as Party;

await partyDoc.setAndSync('status', 'Quotation');
}
}

static getListViewSettings(): ListViewSettings {
return {
columns: [
Expand Down
121 changes: 121 additions & 0 deletions models/baseModels/tests/testLead.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import test from 'tape';
import { closeTestFyo, getTestFyo, setupTestFyo } from 'tests/helpers';
import { ModelNameEnum } from 'models/types';
import { Lead } from '../Lead/Lead';
import { Party } from '../Party/Party';

const fyo = getTestFyo();
setupTestFyo(fyo, __filename);

const leadData = {
name: 'name2',
status: 'Open',
email: 'sample@gmail.com',
mobile: '1234567890',
};

const itemData: { name: string; rate: number } = {
name: 'Pen',
rate: 100,
};

test('create test docs for Lead', async (t) => {
await fyo.doc.getNewDoc(ModelNameEnum.Item, itemData).sync();

t.ok(
fyo.db.exists(ModelNameEnum.Item, itemData.name),
`dummy item ${itemData.name} exists`
);
});

test('create a Lead doc', async (t) => {
await fyo.doc.getNewDoc(ModelNameEnum.Lead, leadData).sync();

t.ok(
fyo.db.exists(ModelNameEnum.Lead, leadData.name),
`${leadData.name} exists`
);
});

test('create Customer from Lead', async (t) => {
const leadDoc = (await fyo.doc.getDoc(ModelNameEnum.Lead, 'name2')) as Lead;

const newCustomer = leadDoc.createCustomer();

t.equals(
leadDoc.status,
'Open',
'status must be Open before Customer is created'
);

await newCustomer.sync();

t.equals(
leadDoc.status,
'Converted',
'status should change to Converted after Customer is created'
);

t.ok(
await fyo.db.exists(ModelNameEnum.Party, newCustomer.name),
'Customer created from Lead'
);
});

test('create SalesQuote', async (t) => {
const leadDoc = (await fyo.doc.getDoc(ModelNameEnum.Lead, 'name2')) as Lead;

const newSalesQuote = leadDoc.createSalesQuote();

newSalesQuote.items = [];
newSalesQuote.append('items', {
item: itemData.name,
quantity: 1,
rate: itemData.rate,
});

t.equals(
leadDoc.status,
'Converted',
'status must be Open before SQUOT is created'
);

await newSalesQuote.sync();
await newSalesQuote.submit();

t.equals(
leadDoc.status,
'Quotation',
'status should change to Quotation after SQUOT submission'
);

t.ok(
await fyo.db.exists(ModelNameEnum.SalesQuote, newSalesQuote.name),
'SalesQuote Created from Lead'
);
});

test('delete Customer then lead status changes to Interested', async (t) => {
const partyDoc = (await fyo.doc.getDoc(
ModelNameEnum.Party,
'name2'
)) as Party;

await partyDoc.delete();

t.equals(
await fyo.db.exists(ModelNameEnum.Party, 'name2'),
false,
'Customer deleted'
);

const leadDoc = (await fyo.doc.getDoc(ModelNameEnum.Lead, 'name2')) as Lead;

t.equals(
leadDoc.status,
'Interested',
'status should change to Interested after Customer is deleted'
);
});

closeTestFyo(fyo, __filename);
Loading

0 comments on commit 7205f5a

Please sign in to comment.