Skip to content

Commit 355341e

Browse files
authored
Merge pull request #237 from hql287/reimplement-invoice-update
Reimplemented invoice update action. Fix #227
2 parents d7c5901 + 90c1450 commit 355341e

File tree

9 files changed

+289
-107
lines changed

9 files changed

+289
-107
lines changed

app/actions/__tests__/invoices.spec.js

+62-10
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ it('getInvoices should create GET_INVOICES action', () => {
77
});
88
});
99

10-
it('saveInvoice should create SAVE_INVOICE action', () => {
10+
it('saveInvoice should create INVOICE_SAVE action', () => {
1111
const invoiceData = {
1212
_id: 'jon_snow',
1313
fulname: 'Jon Snow',
@@ -19,21 +19,73 @@ it('saveInvoice should create SAVE_INVOICE action', () => {
1919
});
2020
});
2121

22-
it('deleteInvoice should create DELETE_INVOICE action', () => {
22+
it('newInvoiceFromContact should create INVOICE_NEW_FROM_CONTACT action', () => {
23+
const contactData = {
24+
_id: 'jon_snow',
25+
fulname: 'Jon Snow',
26+
27+
};
28+
expect(actions.newInvoiceFromContact(contactData)).toEqual({
29+
type: ACTION_TYPES.INVOICE_NEW_FROM_CONTACT,
30+
payload: contactData,
31+
});
32+
});
33+
34+
it('deleteInvoice should create INVOICE_DELETE action', () => {
2335
expect(actions.deleteInvoice('jon_snow')).toEqual({
2436
type: ACTION_TYPES.INVOICE_DELETE,
2537
payload: 'jon_snow',
2638
});
2739
});
2840

29-
it('newInvoiceFromContact should create INVOICE_NEW_FROM_CONTACT action', () => {
30-
const contact = {
31-
id: 'abcxyz',
32-
name: 'Jon Snow',
33-
company: 'HBO',
41+
it('editInvoice should create INVOICE_EDIT action', () => {
42+
const invoiceData = {
43+
_id: 'jon_snow',
44+
fulname: 'Jon Snow',
45+
3446
};
35-
expect(actions.newInvoiceFromContact(contact)).toEqual({
36-
type: ACTION_TYPES.INVOICE_NEW_FROM_CONTACT,
37-
payload: contact,
47+
expect(actions.editInvoice(invoiceData)).toEqual({
48+
type: ACTION_TYPES.INVOICE_EDIT,
49+
payload: invoiceData,
50+
});
51+
});
52+
53+
it('updateInvoice should create INVOICE_UPDATE action', () => {
54+
const invoiceData = {
55+
_id: 'jon_snow',
56+
fulname: 'Jon Snow',
57+
58+
};
59+
expect(actions.updateInvoice(invoiceData)).toEqual({
60+
type: ACTION_TYPES.INVOICE_UPDATE,
61+
payload: invoiceData,
62+
});
63+
});
64+
65+
it('setInvoiceStatus should create INVOICE_SET_STATUS action', () => {
66+
const invoiceID = 'jon_snow';
67+
const status = 'pending';
68+
expect(actions.setInvoiceStatus(invoiceID, status)).toEqual({
69+
type: ACTION_TYPES.INVOICE_SET_STATUS,
70+
payload: {
71+
invoiceID: 'jon_snow',
72+
status: 'pending',
73+
},
74+
});
75+
});
76+
77+
it('saveInvoiceConfigs should create INVOICE_CONFIGS_SAVE action', () => {
78+
const invoiceID = 'jon_snow';
79+
const configs = {
80+
color: 'red'
81+
};
82+
expect(actions.saveInvoiceConfigs(invoiceID, configs)).toEqual({
83+
type: ACTION_TYPES.INVOICE_CONFIGS_SAVE,
84+
payload: {
85+
invoiceID: 'jon_snow',
86+
configs: {
87+
color: 'red'
88+
}
89+
}
3890
});
3991
});

app/actions/invoices.jsx

+14-20
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,39 @@
11
import * as ACTION_TYPES from '../constants/actions.jsx';
22
import { createAction } from 'redux-actions';
33

4-
// Get All Invoices
54
export const getInvoices = createAction(ACTION_TYPES.INVOICE_GET_ALL);
65

7-
// Save an Invoice
86
export const saveInvoice = createAction(
97
ACTION_TYPES.INVOICE_SAVE,
108
invoiceData => invoiceData
119
);
1210

13-
export const saveInvoiceConfigs = createAction(
14-
ACTION_TYPES.INVOICE_CONFIGS_SAVE,
15-
(invoiceID, configs) => ({ invoiceID, configs })
11+
export const newInvoiceFromContact = createAction(
12+
ACTION_TYPES.INVOICE_NEW_FROM_CONTACT,
13+
contact => contact
14+
);
15+
16+
export const deleteInvoice = createAction(
17+
ACTION_TYPES.INVOICE_DELETE,
18+
invoiceID => invoiceID
1619
);
1720

18-
// Edit an Invoice
1921
export const editInvoice = createAction(
2022
ACTION_TYPES.INVOICE_EDIT,
2123
invoiceData => invoiceData
2224
);
2325

2426
export const updateInvoice = createAction(
2527
ACTION_TYPES.INVOICE_UPDATE,
26-
(invoiceID, data) => ({ invoiceID, data })
27-
);
28-
29-
// New Invoice from Contact
30-
export const newInvoiceFromContact = createAction(
31-
ACTION_TYPES.INVOICE_NEW_FROM_CONTACT,
32-
contact => contact
28+
updatedInvoice => updatedInvoice
3329
);
3430

35-
// Delete an invoice
36-
export const deleteInvoice = createAction(
37-
ACTION_TYPES.INVOICE_DELETE,
38-
invoiceID => invoiceID
39-
);
40-
41-
// set the status of an invoice (pending/paid/etc.)
4231
export const setInvoiceStatus = createAction(
4332
ACTION_TYPES.INVOICE_SET_STATUS,
4433
(invoiceID, status) => ({ invoiceID, status })
4534
);
35+
36+
export const saveInvoiceConfigs = createAction(
37+
ACTION_TYPES.INVOICE_CONFIGS_SAVE,
38+
(invoiceID, configs) => ({ invoiceID, configs })
39+
);

app/helpers/__mocks__/pouchDB.js

+11
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ const updateDoc = jest.fn(
6262
})
6363
);
6464

65+
const getSingleDoc = jest.fn(
66+
(dbName, docID) =>
67+
new Promise((resolve, reject) => {
68+
!dbName && reject(new Error('No database found!'));
69+
!docID && reject(new Error('No docID found!'));
70+
dbName === 'contacts' && resolve([...mockData.contactsRecords][0]);
71+
dbName === 'invoices' && resolve([...mockData.invoicesRecords][0]);
72+
})
73+
);
74+
6575
const deleteDoc = jest.fn(
6676
(dbName, docId) =>
6777
new Promise((resolve, reject) => {
@@ -83,6 +93,7 @@ const deleteDoc = jest.fn(
8393

8494
module.exports = {
8595
getAllDocs,
96+
getSingleDoc,
8697
saveDoc,
8798
updateDoc,
8899
deleteDoc,

app/helpers/__tests__/form.spec.js

+31
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import faker from 'faker';
33
import uuidv4 from 'uuid/v4';
44
import i18n from '../../../i18n/i18n';
5+
import omit from 'lodash';
56

67
// Helpers to test
78
import {
@@ -267,6 +268,36 @@ describe('getInvoiceData', () => {
267268
const invoiceData = getInvoiceData(newFormData);
268269
expect(invoiceData.invoiceID).toEqual('Invoice: 123-456-789');
269270
});
271+
272+
it('should return correct metadata on editMode', () => {
273+
const invoiceID = uuidv4();
274+
const invoiceRev = uuidv4();
275+
const createdDate = Date.now();
276+
const newFormData = Object.assign({}, formData, {
277+
settings: Object.assign({}, formData.settings, {
278+
editMode: Object.assign({}, formData.settings.editMode, {
279+
active: true,
280+
data: Object.assign({}, omit(formData, ['settings, savedSettings']),
281+
{
282+
_id: invoiceID,
283+
_rev: invoiceRev,
284+
created_at: createdDate
285+
}
286+
)
287+
}),
288+
}),
289+
});
290+
const invoiceData = getInvoiceData(newFormData);
291+
expect(invoiceData._id).toEqual(invoiceID);
292+
expect(invoiceData._rev).toEqual(invoiceRev);
293+
expect(invoiceData.created_at).toEqual(createdDate);
294+
});
295+
296+
// TODO
297+
it('set status as pending when creating a new invoice');
298+
it('always generate _id when creating a new invoice');
299+
it('does not include _rev when creating a new invoice');
300+
it('always recalculate subTotal and grandTotal');
270301
});
271302

272303
describe('validateFormData', () => {

app/helpers/form.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,12 @@ function getInvoiceData(formData) {
7777

7878
// Return final value
7979
return Object.assign({}, invoiceData, {
80-
// Reuse existing data
80+
// Metadata
8181
_id: editMode.active ? editMode.data._id : uuidv4(),
82+
_rev: editMode.active ? editMode.data._rev : null,
8283
created_at: editMode.active ? editMode.data.created_at : Date.now(),
8384
status: editMode.active ? editMode.data.status: 'pending',
84-
// Calculate subtotal & grandTotal
85+
// Alway calculate subtotal & grandTotal
8586
subtotal: getInvoiceValue(invoiceData).subtotal,
8687
grandTotal: getInvoiceValue(invoiceData).grandTotal,
8788
});

app/helpers/pouchDB.js

+6-10
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ const invoicesMigrations = {
6969
placement: 'before',
7070
separator: 'commaDot',
7171
fraction: 2,
72-
}
72+
},
7373
});
7474
return newDoc;
7575
},
@@ -81,9 +81,9 @@ const invoicesMigrations = {
8181
dueDate: {
8282
selectedDate: doc.dueDate,
8383
useCustom: true,
84-
}
84+
},
8585
});
86-
}
86+
},
8787
};
8888

8989
runMigration(
@@ -176,17 +176,13 @@ const deleteDoc = (dbName, doc) =>
176176
});
177177

178178
// Update A Document
179-
const updateDoc = (dbName, docId, updatedDoc) =>
179+
const updateDoc = (dbName, updatedDoc) =>
180180
new Promise((resolve, reject) => {
181181
setDB(dbName)
182182
.then(db =>
183183
db
184-
.get(docId)
185-
.then(record =>
186-
db
187-
.put(Object.assign(record, updatedDoc))
188-
.then(getAllDocs(dbName).then(allDocs => resolve(allDocs)))
189-
)
184+
.put(updatedDoc)
185+
.then(getAllDocs(dbName).then(allDocs => resolve(allDocs)))
190186
)
191187
.catch(err => reject(err));
192188
});

app/middlewares/FormMW.jsx

+3-4
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,14 @@ const FormMW = ({ dispatch, getState }) => next => action => {
2323
// Validate Form Data
2424
if (!validateFormData(currentFormData)) return;
2525
const currentInvoiceData = getInvoiceData(currentFormData);
26-
// Check Edit Mode
26+
// UPDATE DOC
2727
if (currentFormData.settings.editMode.active) {
28-
const invoiceId = currentFormData.settings.editMode.data._id;
2928
// Update existing invoice
30-
dispatch(InvoicesActions.updateInvoice(invoiceId, currentInvoiceData));
29+
dispatch(InvoicesActions.updateInvoice(currentInvoiceData));
3130
// Change Tab to invoices
3231
dispatch(UIActions.changeActiveTab('invoices'));
3332
} else {
34-
// Save Invoice To DB
33+
// CREATE DOC
3534
dispatch(InvoicesActions.saveInvoice(currentInvoiceData));
3635
}
3736
// Save Contact to DB if it's a new one

0 commit comments

Comments
 (0)