├── .gitignore ├── .gitattributes ├── screens ├── admin1.png ├── login.png ├── user.png ├── workflow.png ├── create-user.png ├── create-batch.png ├── user-update-user.png ├── perform-exporting.png ├── perform-harvesting.png ├── perform-importing.png ├── perform-processing.png ├── Batch-Details-complited.png ├── perform-farm-inspection.png └── coffeeSupplychain-inprogress.png ├── migrations ├── 1_initial_migration.js └── 2_deploy_contracts.js ├── contracts ├── README.txt ├── Migrations.sol ├── Ownable.sol ├── SupplyChainStorageOwnable.sol ├── SupplyChainUser.sol ├── CoffeeSupplyChain.sol └── SupplyChainStorage.sol ├── truffle.js ├── package.json ├── test ├── supply_chain_storage.js ├── supply_chain_user.js └── coffee_supply_chain.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | build/* 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity -------------------------------------------------------------------------------- /screens/admin1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwaltzsoftware-org/coffee-supplychain-ethereum/HEAD/screens/admin1.png -------------------------------------------------------------------------------- /screens/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwaltzsoftware-org/coffee-supplychain-ethereum/HEAD/screens/login.png -------------------------------------------------------------------------------- /screens/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwaltzsoftware-org/coffee-supplychain-ethereum/HEAD/screens/user.png -------------------------------------------------------------------------------- /screens/workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwaltzsoftware-org/coffee-supplychain-ethereum/HEAD/screens/workflow.png -------------------------------------------------------------------------------- /screens/create-user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwaltzsoftware-org/coffee-supplychain-ethereum/HEAD/screens/create-user.png -------------------------------------------------------------------------------- /screens/create-batch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwaltzsoftware-org/coffee-supplychain-ethereum/HEAD/screens/create-batch.png -------------------------------------------------------------------------------- /screens/user-update-user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwaltzsoftware-org/coffee-supplychain-ethereum/HEAD/screens/user-update-user.png -------------------------------------------------------------------------------- /screens/perform-exporting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwaltzsoftware-org/coffee-supplychain-ethereum/HEAD/screens/perform-exporting.png -------------------------------------------------------------------------------- /screens/perform-harvesting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwaltzsoftware-org/coffee-supplychain-ethereum/HEAD/screens/perform-harvesting.png -------------------------------------------------------------------------------- /screens/perform-importing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwaltzsoftware-org/coffee-supplychain-ethereum/HEAD/screens/perform-importing.png -------------------------------------------------------------------------------- /screens/perform-processing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwaltzsoftware-org/coffee-supplychain-ethereum/HEAD/screens/perform-processing.png -------------------------------------------------------------------------------- /screens/Batch-Details-complited.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwaltzsoftware-org/coffee-supplychain-ethereum/HEAD/screens/Batch-Details-complited.png -------------------------------------------------------------------------------- /screens/perform-farm-inspection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwaltzsoftware-org/coffee-supplychain-ethereum/HEAD/screens/perform-farm-inspection.png -------------------------------------------------------------------------------- /screens/coffeeSupplychain-inprogress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwaltzsoftware-org/coffee-supplychain-ethereum/HEAD/screens/coffeeSupplychain-inprogress.png -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require("./Migrations.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /contracts/README.txt: -------------------------------------------------------------------------------- 1 | 1. Deploy storage contract 2 | 2. copy address of deployed storage contract 3 | 3. Deploy user contract with storage contract address 4 | 4. Deploy coffeeSupplychain contract with storage contract address 5 | 5. Go to Storage contract 6 | 6. Authorized caller - means copy user contract address and past in authorized() method 7 | 7. Authorized caller - means copy coffee Supply chain contract address and past in authorized() method 8 | 8. Now our contract is ready and we can use that. -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /truffle.js: -------------------------------------------------------------------------------- 1 | var HDWalletProvider = require("truffle-hdwallet-provider"); 2 | module.exports = 3 | { 4 | networks: 5 | { 6 | development: 7 | { 8 | host: "localhost", 9 | port: 8545, 10 | network_id: "*" // Match any network id 11 | }, 12 | rinkeby: { 13 | provider: function() { 14 | var mnemonic = "steel neither fatigue ...";//put ETH wallet 12 mnemonic code 15 | return new HDWalletProvider(mnemonic, "https://rinkeby.infura.io/8U0AE4DUGSh8lVO3zmma"); 16 | }, 17 | network_id: '4', 18 | from: '0xab0874cb61d.....',/*ETH wallet 12 mnemonic code wallet address*/ 19 | } 20 | } 21 | }; -------------------------------------------------------------------------------- /migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | var SupplyChainStorage = artifacts.require("./SupplyChainStorage"); 2 | var CoffeeSupplyChain = artifacts.require("./CoffeeSupplyChain"); 3 | var SupplyChainUser = artifacts.require("./SupplyChainUser"); 4 | 5 | 6 | module.exports = function(deployer){ 7 | deployer.deploy(SupplyChainStorage) 8 | .then(()=>{ 9 | return deployer.deploy(CoffeeSupplyChain,SupplyChainStorage.address); 10 | }) 11 | .then(()=>{ 12 | return deployer.deploy(SupplyChainUser,SupplyChainStorage.address); 13 | }) 14 | .then(()=>{ 15 | return SupplyChainStorage.deployed(); 16 | }).then(async function(instance){ 17 | await instance.authorizeCaller(CoffeeSupplyChain.address); 18 | await instance.authorizeCaller(SupplyChainUser.address); 19 | return instance; 20 | }) 21 | .catch(function(error) 22 | { 23 | console.log(error); 24 | }); 25 | }; 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coffee-supplychain-contract", 3 | "version": "1.0.0", 4 | "description": "This project showcases the journey of coffee beans on blockchain.", 5 | "main": "truffle.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+ssh://git@gitlab.com/vikas_imperialsoftech/coffee-supplychain-contract.git" 15 | }, 16 | "author": "Imperial Softech", 17 | "license": "ISC", 18 | "bugs": { 19 | "url": "https://gitlab.com/vikas_imperialsoftech/coffee-supplychain-contract/issues" 20 | }, 21 | "homepage": "https://gitlab.com/vikas_imperialsoftech/coffee-supplychain-contract#README", 22 | "dependencies": { 23 | "chai": "^4.1.2", 24 | "eth-gas-reporter": "^0.1.7", 25 | "ethereumjs-abi": "^0.6.5", 26 | "growl": "^1.10.5", 27 | "truffle-hdwallet-provider": "0.0.5" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /contracts/Ownable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | /** 5 | * @title Ownable 6 | * @dev The Ownable contract has an owner address, and provides basic authorization control 7 | * functions, this simplifies the implementation of "user permissions". 8 | */ 9 | contract Ownable { 10 | address public owner; 11 | 12 | 13 | event OwnershipRenounced(address indexed previousOwner); 14 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 15 | 16 | 17 | /** 18 | * @dev The Ownable constructor sets the original `owner` of the contract to the sender 19 | * account. 20 | */ 21 | constructor() public { 22 | owner = msg.sender; 23 | } 24 | 25 | /** 26 | * @dev Throws if called by any account other than the owner. 27 | */ 28 | modifier onlyOwner() { 29 | require(msg.sender == owner); 30 | _; 31 | } 32 | 33 | /** 34 | * @dev Allows the current owner to transfer control of the contract to a newOwner. 35 | * @param newOwner The address to transfer ownership to. 36 | */ 37 | function transferOwnership(address newOwner) public onlyOwner { 38 | require(newOwner != address(0)); 39 | emit OwnershipTransferred(owner, newOwner); 40 | owner = newOwner; 41 | } 42 | 43 | /** 44 | * @dev Allows the current owner to relinquish control of the contract. 45 | */ 46 | function renounceOwnership() public onlyOwner { 47 | emit OwnershipRenounced(owner); 48 | owner = address(0); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /contracts/SupplyChainStorageOwnable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | /** 5 | * @title Ownable 6 | * @dev The Ownable contract has an owner address, and provides basic authorization control 7 | * functions, this simplifies the implementation of "user permissions". 8 | */ 9 | contract SupplyChainStorageOwnable { 10 | address public owner; 11 | 12 | 13 | event OwnershipRenounced(address indexed previousOwner); 14 | event OwnershipTransferred( 15 | address indexed previousOwner, 16 | address indexed newOwner 17 | ); 18 | 19 | 20 | /** 21 | * @dev The Ownable constructor sets the original `owner` of the contract to the sender 22 | * account. 23 | */ 24 | constructor() public { 25 | owner = msg.sender; 26 | } 27 | 28 | /** 29 | * @dev Throws if called by any account other than the owner. 30 | */ 31 | modifier onlyOwner() { 32 | require(msg.sender == owner); 33 | _; 34 | } 35 | 36 | /** 37 | * @dev Allows the current owner to transfer control of the contract to a newOwner. 38 | * @param newOwner The address to transfer ownership to. 39 | */ 40 | function transferOwnership(address newOwner) public onlyOwner { 41 | require(newOwner != address(0)); 42 | emit OwnershipTransferred(owner, newOwner); 43 | owner = newOwner; 44 | } 45 | 46 | /** 47 | * @dev Allows the current owner to relinquish control of the contract. 48 | */ 49 | function renounceOwnership() public onlyOwner { 50 | emit OwnershipRenounced(owner); 51 | owner = address(0); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /contracts/SupplyChainUser.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | import "./SupplyChainStorage.sol"; 3 | import "./Ownable.sol"; 4 | 5 | contract SupplyChainUser is Ownable 6 | { 7 | /*Events*/ 8 | event UserUpdate(address indexed user, string name, string contactNo, string role, bool isActive, string profileHash); 9 | event UserRoleUpdate(address indexed user, string role); 10 | 11 | /* Storage Variables */ 12 | SupplyChainStorage supplyChainStorage; 13 | 14 | constructor(address _supplyChainAddress) public { 15 | supplyChainStorage = SupplyChainStorage(_supplyChainAddress); 16 | } 17 | 18 | 19 | /* Create/Update User */ 20 | 21 | function updateUser(string _name, string _contactNo, string _role, bool _isActive,string _profileHash) public returns(bool) 22 | { 23 | require(msg.sender != address(0)); 24 | 25 | /* Call Storage Contract */ 26 | bool status = supplyChainStorage.setUser(msg.sender, _name, _contactNo, _role, _isActive,_profileHash); 27 | 28 | /*call event*/ 29 | emit UserUpdate(msg.sender,_name,_contactNo,_role,_isActive,_profileHash); 30 | emit UserRoleUpdate(msg.sender,_role); 31 | 32 | return status; 33 | } 34 | 35 | /* Create/Update User For Admin */ 36 | function updateUserForAdmin(address _userAddress, string _name, string _contactNo, string _role, bool _isActive,string _profileHash) public onlyOwner returns(bool) 37 | { 38 | require(_userAddress != address(0)); 39 | 40 | /* Call Storage Contract */ 41 | bool status = supplyChainStorage.setUser(_userAddress, _name, _contactNo, _role, _isActive, _profileHash); 42 | 43 | /*call event*/ 44 | emit UserUpdate(_userAddress,_name,_contactNo,_role,_isActive,_profileHash); 45 | emit UserRoleUpdate(_userAddress,_role); 46 | 47 | return status; 48 | } 49 | 50 | /* get User */ 51 | function getUser(address _userAddress) public view returns(string name, string contactNo, string role, bool isActive , string profileHash){ 52 | require(_userAddress != address(0)); 53 | 54 | /*Getting value from struct*/ 55 | (name, contactNo, role, isActive, profileHash) = supplyChainStorage.getUser(_userAddress); 56 | 57 | return (name, contactNo, role, isActive, profileHash); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /test/supply_chain_storage.js: -------------------------------------------------------------------------------- 1 | const SupplyChainStorage = artifacts.require("../contracts/SupplyChainStorage.sol"); 2 | 3 | const assert = require('chai').assert; 4 | 5 | /*Define common variables for unit testing*/ 6 | const _name = 'Ram'; 7 | const _contactNo = '9876543210'; 8 | const _role = 'HARVESTER'; 9 | const _isActive = true; 10 | const _profileHash = 'Qmadp4L61MaQQX5NFfjqaihnY8r7PmogqZL6wvX1HqwL'; 11 | 12 | contract('SupplyChainStorage',function(accounts) 13 | { 14 | const spenderAddress = accounts[0]; 15 | const authorizedCaller = accounts[1]; 16 | const userAddress = accounts[2]; 17 | 18 | beforeEach(async() => { 19 | this.storageContract = await SupplyChainStorage.new({from:spenderAddress}); 20 | 21 | // await this.storageContract.authorizeCaller(this.storageContract.address,{from:spenderAddress}); 22 | }); 23 | 24 | describe('Authorize Caller',() => { 25 | it('should Authorize', async() => { 26 | 27 | const {logs} = await this.storageContract.authorizeCaller(authorizedCaller,{from: spenderAddress}); 28 | 29 | const authorizedCallerEvent = logs.find(e => e.event === 'AuthorizedCaller'); 30 | assert.exists(authorizedCallerEvent,"AuthorizedCaller does not exists"); 31 | }); 32 | }); 33 | 34 | describe('DeAuthorize Caller',() => { 35 | it('should DeAuthorize', async() => { 36 | 37 | const {logs} = await this.storageContract.deAuthorizeCaller(authorizedCaller,{from: spenderAddress}); 38 | 39 | const deAuthorizedCallerEvent = logs.find(e => e.event === 'DeAuthorizedCaller'); 40 | assert.exists(deAuthorizedCallerEvent,"DeAuthorizedCaller does not exists"); 41 | }); 42 | }); 43 | 44 | describe('User Set',() => { 45 | it('should Add/Update New User', async() => { 46 | 47 | const {logs} = await this.storageContract.setUser(userAddress, 48 | _name, 49 | _contactNo, 50 | _role, 51 | _isActive, 52 | _profileHash, 53 | {from: spenderAddress}); 54 | 55 | checkUserExists(logs,function(result){}); 56 | 57 | const user = await this.storageContract.getUser(userAddress); 58 | 59 | checkUserData(user,function(result){}); 60 | }); 61 | }); 62 | 63 | }); 64 | 65 | function checkUserExists(logs,callback){ 66 | 67 | const updateUserEvent = logs.find(e => e.event === 'UserUpdate'); 68 | assert.exists(updateUserEvent,"UserUpdate does not exists"); 69 | 70 | const updateUserRoleEvent = logs.find(e => e.event === 'UserRoleUpdate'); 71 | assert.exists(updateUserRoleEvent,"UserRoleUpdate does not exists"); 72 | 73 | callback(true); 74 | } 75 | 76 | function checkUserData(user,callback){ 77 | 78 | assert.equal(user[0],_name,"Name checked:"); 79 | assert.equal(user[1],_contactNo,"Contact No checked:"); 80 | assert.equal(user[2],_role,"Role checked:"); 81 | assert.equal(user[3],_isActive,"isActive checked:"); 82 | assert.equal(user[4],_profileHash,"Profile Hash checked:"); 83 | assert.isTrue(true); 84 | 85 | callback(true); 86 | } -------------------------------------------------------------------------------- /test/supply_chain_user.js: -------------------------------------------------------------------------------- 1 | const SupplyChainUser = artifacts.require('../contracts/SupplyChainUser'); 2 | const SupplyChainStorage = artifacts.require('../contracts/SupplyChainStorage'); 3 | 4 | const assert = require('chai').assert; 5 | 6 | /*Define common variables for unit testing*/ 7 | const _name = 'Ram'; 8 | const _contactNo = '9876543210'; 9 | const _role = 'HARVESTER'; 10 | const _isActive = true; 11 | const _profileHash = 'Qmadp4L61MaQQX5NFfjqaihnY8r7PmogqZL6wvX1HqwL'; 12 | 13 | contract('SupplyChainUser', function(accounts) { 14 | 15 | /*Define common variables for unit testing*/ 16 | const spenderAddress = accounts[0]; 17 | const userAddress = accounts[1]; 18 | 19 | beforeEach(async() => { 20 | this.storageContract = await SupplyChainStorage.new({from:spenderAddress}); 21 | this.userContract = await SupplyChainUser.new(this.storageContract.address,{from:spenderAddress}); 22 | 23 | await this.storageContract.authorizeCaller(this.userContract.address,{from:spenderAddress}); 24 | }); 25 | 26 | describe('User Update',() => { 27 | it('should Add/Update New User', async() => { 28 | 29 | const {logs} = await this.userContract.updateUser(_name, 30 | _contactNo, 31 | _role, 32 | _isActive, 33 | _profileHash, 34 | {from: userAddress}); 35 | 36 | checkUserExists(logs,function(result){}); 37 | 38 | const user = await this.userContract.getUser(userAddress); 39 | 40 | checkUserData(user,function(result){}); 41 | }); 42 | }); 43 | 44 | describe('User Update from Admin', ()=>{ 45 | it('should Add/Update New User from Admin', async() =>{ 46 | 47 | const {logs} = await this.userContract.updateUserForAdmin(userAddress, 48 | _name, 49 | _contactNo, 50 | _role, 51 | _isActive, 52 | _profileHash, 53 | {from: spenderAddress}); 54 | 55 | 56 | checkUserExists(logs,function(result){}); 57 | 58 | const user = await this.userContract.getUser(userAddress); 59 | 60 | checkUserData(user,function(result){}); 61 | }); 62 | }); 63 | 64 | describe('User Details Get', ()=>{ 65 | it('should all Get User Details', async()=>{ 66 | 67 | const {logs} = await this.userContract.updateUserForAdmin(userAddress, 68 | _name, 69 | _contactNo, 70 | _role, 71 | _isActive, 72 | _profileHash, 73 | {from: spenderAddress}); 74 | 75 | checkUserExists(logs,function(result){}); 76 | 77 | const user = await this.userContract.getUser(userAddress); 78 | 79 | checkUserData(user,function(result){}); 80 | }); 81 | }); 82 | 83 | }); 84 | 85 | function checkUserExists(logs,callback){ 86 | 87 | const updateUserEvent = logs.find(e => e.event === 'UserUpdate'); 88 | assert.exists(updateUserEvent,"UserUpdate does not exists"); 89 | 90 | const updateUserRoleEvent = logs.find(e => e.event === 'UserRoleUpdate'); 91 | assert.exists(updateUserRoleEvent,"UserRoleUpdate does not exists"); 92 | 93 | callback(true); 94 | } 95 | 96 | function checkUserData(user,callback){ 97 | 98 | assert.equal(user[0],_name,"Name checked:"); 99 | assert.equal(user[1],_contactNo,"Contact No checked:"); 100 | assert.equal(user[2],_role,"Role checked:"); 101 | assert.equal(user[3],_isActive,"isActive checked:"); 102 | assert.equal(user[4],_profileHash,"Profile Hash checked:"); 103 | assert.isTrue(true); 104 | 105 | callback(true); 106 | } -------------------------------------------------------------------------------- /contracts/CoffeeSupplyChain.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | import "./SupplyChainStorage.sol"; 3 | import "./Ownable.sol"; 4 | 5 | contract CoffeeSupplyChain is Ownable 6 | { 7 | 8 | event PerformCultivation(address indexed user, address indexed batchNo); 9 | event DoneInspection(address indexed user, address indexed batchNo); 10 | event DoneHarvesting(address indexed user, address indexed batchNo); 11 | event DoneExporting(address indexed user, address indexed batchNo); 12 | event DoneImporting(address indexed user, address indexed batchNo); 13 | event DoneProcessing(address indexed user, address indexed batchNo); 14 | 15 | 16 | /*Modifier*/ 17 | modifier isValidPerformer(address batchNo, string role) { 18 | 19 | require(keccak256(supplyChainStorage.getUserRole(msg.sender)) == keccak256(role)); 20 | require(keccak256(supplyChainStorage.getNextAction(batchNo)) == keccak256(role)); 21 | _; 22 | } 23 | 24 | /* Storage Variables */ 25 | SupplyChainStorage supplyChainStorage; 26 | 27 | constructor(address _supplyChainAddress) public { 28 | supplyChainStorage = SupplyChainStorage(_supplyChainAddress); 29 | } 30 | 31 | 32 | /* Get Next Action */ 33 | 34 | function getNextAction(address _batchNo) public view returns(string action) 35 | { 36 | (action) = supplyChainStorage.getNextAction(_batchNo); 37 | return (action); 38 | } 39 | 40 | 41 | /* get Basic Details */ 42 | 43 | function getBasicDetails(address _batchNo) public view returns (string registrationNo, 44 | string farmerName, 45 | string farmAddress, 46 | string exporterName, 47 | string importerName) { 48 | /* Call Storage Contract */ 49 | (registrationNo, farmerName, farmAddress, exporterName, importerName) = supplyChainStorage.getBasicDetails(_batchNo); 50 | return (registrationNo, farmerName, farmAddress, exporterName, importerName); 51 | } 52 | 53 | /* perform Basic Cultivation */ 54 | 55 | function addBasicDetails(string _registrationNo, 56 | string _farmerName, 57 | string _farmAddress, 58 | string _exporterName, 59 | string _importerName 60 | ) public onlyOwner returns(address) { 61 | 62 | address batchNo = supplyChainStorage.setBasicDetails(_registrationNo, 63 | _farmerName, 64 | _farmAddress, 65 | _exporterName, 66 | _importerName); 67 | 68 | emit PerformCultivation(msg.sender, batchNo); 69 | 70 | return (batchNo); 71 | } 72 | 73 | /* get Farm Inspection */ 74 | 75 | function getFarmInspectorData(address _batchNo) public view returns (string coffeeFamily,string typeOfSeed,string fertilizerUsed) { 76 | /* Call Storage Contract */ 77 | (coffeeFamily, typeOfSeed, fertilizerUsed) = supplyChainStorage.getFarmInspectorData(_batchNo); 78 | return (coffeeFamily, typeOfSeed, fertilizerUsed); 79 | } 80 | 81 | /* perform Farm Inspection */ 82 | 83 | function updateFarmInspectorData(address _batchNo, 84 | string _coffeeFamily, 85 | string _typeOfSeed, 86 | string _fertilizerUsed) 87 | public isValidPerformer(_batchNo,'FARM_INSPECTION') returns(bool) { 88 | /* Call Storage Contract */ 89 | bool status = supplyChainStorage.setFarmInspectorData(_batchNo, _coffeeFamily, _typeOfSeed, _fertilizerUsed); 90 | 91 | emit DoneInspection(msg.sender, _batchNo); 92 | return (status); 93 | } 94 | 95 | 96 | /* get Harvest */ 97 | 98 | function getHarvesterData(address _batchNo) public view returns (string cropVariety, string temperatureUsed, string humidity) { 99 | /* Call Storage Contract */ 100 | (cropVariety, temperatureUsed, humidity) = supplyChainStorage.getHarvesterData(_batchNo); 101 | return (cropVariety, temperatureUsed, humidity); 102 | } 103 | 104 | /* perform Harvest */ 105 | 106 | function updateHarvesterData(address _batchNo, 107 | string _cropVariety, 108 | string _temperatureUsed, 109 | string _humidity) 110 | public isValidPerformer(_batchNo,'HARVESTER') returns(bool) { 111 | 112 | /* Call Storage Contract */ 113 | bool status = supplyChainStorage.setHarvesterData(_batchNo, _cropVariety, _temperatureUsed, _humidity); 114 | 115 | emit DoneHarvesting(msg.sender, _batchNo); 116 | return (status); 117 | } 118 | 119 | /* get Export */ 120 | 121 | function getExporterData(address _batchNo) public view returns (uint256 quantity, 122 | string destinationAddress, 123 | string shipName, 124 | string shipNo, 125 | uint256 departureDateTime, 126 | uint256 estimateDateTime, 127 | uint256 exporterId) { 128 | /* Call Storage Contract */ 129 | (quantity, 130 | destinationAddress, 131 | shipName, 132 | shipNo, 133 | departureDateTime, 134 | estimateDateTime, 135 | exporterId) = supplyChainStorage.getExporterData(_batchNo); 136 | 137 | return (quantity, 138 | destinationAddress, 139 | shipName, 140 | shipNo, 141 | departureDateTime, 142 | estimateDateTime, 143 | exporterId); 144 | } 145 | 146 | /* perform Export */ 147 | 148 | function updateExporterData(address _batchNo, 149 | uint256 _quantity, 150 | string _destinationAddress, 151 | string _shipName, 152 | string _shipNo, 153 | uint256 _estimateDateTime, 154 | uint256 _exporterId) 155 | public isValidPerformer(_batchNo,'EXPORTER') returns(bool) { 156 | 157 | /* Call Storage Contract */ 158 | bool status = supplyChainStorage.setExporterData(_batchNo, _quantity, _destinationAddress, _shipName,_shipNo, _estimateDateTime,_exporterId); 159 | 160 | emit DoneExporting(msg.sender, _batchNo); 161 | return (status); 162 | } 163 | 164 | /* get Import */ 165 | 166 | function getImporterData(address _batchNo) public view returns (uint256 quantity, 167 | string shipName, 168 | string shipNo, 169 | uint256 arrivalDateTime, 170 | string transportInfo, 171 | string warehouseName, 172 | string warehouseAddress, 173 | uint256 importerId) { 174 | /* Call Storage Contract */ 175 | (quantity, 176 | shipName, 177 | shipNo, 178 | arrivalDateTime, 179 | transportInfo, 180 | warehouseName, 181 | warehouseAddress, 182 | importerId) = supplyChainStorage.getImporterData(_batchNo); 183 | 184 | return (quantity, 185 | shipName, 186 | shipNo, 187 | arrivalDateTime, 188 | transportInfo, 189 | warehouseName, 190 | warehouseAddress, 191 | importerId); 192 | 193 | } 194 | 195 | /* perform Import */ 196 | 197 | function updateImporterData(address _batchNo, 198 | uint256 _quantity, 199 | string _shipName, 200 | string _shipNo, 201 | string _transportInfo, 202 | string _warehouseName, 203 | string _warehouseAddress, 204 | uint256 _importerId) 205 | public isValidPerformer(_batchNo,'IMPORTER') returns(bool) { 206 | 207 | /* Call Storage Contract */ 208 | bool status = supplyChainStorage.setImporterData(_batchNo, _quantity, _shipName, _shipNo, _transportInfo,_warehouseName,_warehouseAddress,_importerId); 209 | 210 | emit DoneImporting(msg.sender, _batchNo); 211 | return (status); 212 | } 213 | 214 | 215 | /* get Processor */ 216 | 217 | function getProcessorData(address _batchNo) public view returns (uint256 quantity, 218 | string temperature, 219 | uint256 rostingDuration, 220 | string internalBatchNo, 221 | uint256 packageDateTime, 222 | string processorName, 223 | string processorAddress) { 224 | /* Call Storage Contract */ 225 | (quantity, 226 | temperature, 227 | rostingDuration, 228 | internalBatchNo, 229 | packageDateTime, 230 | processorName, 231 | processorAddress) = supplyChainStorage.getProcessorData(_batchNo); 232 | 233 | return (quantity, 234 | temperature, 235 | rostingDuration, 236 | internalBatchNo, 237 | packageDateTime, 238 | processorName, 239 | processorAddress); 240 | 241 | } 242 | 243 | /* perform Processing */ 244 | 245 | function updateProcessorData(address _batchNo, 246 | uint256 _quantity, 247 | string _temperature, 248 | uint256 _rostingDuration, 249 | string _internalBatchNo, 250 | uint256 _packageDateTime, 251 | string _processorName, 252 | string _processorAddress) public isValidPerformer(_batchNo,'PROCESSOR') returns(bool) { 253 | 254 | /* Call Storage Contract */ 255 | bool status = supplyChainStorage.setProcessorData(_batchNo, 256 | _quantity, 257 | _temperature, 258 | _rostingDuration, 259 | _internalBatchNo, 260 | _packageDateTime, 261 | _processorName, 262 | _processorAddress); 263 | 264 | emit DoneProcessing(msg.sender, _batchNo); 265 | return (status); 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Implementation of Coffee Supplychain using Ethereum Smart Contract 2 | 3 | This project showcases the journey of coffee beans on blockchain. 4 | 5 | The coffee supply chain is the sequence of activities and process to bring raw coffee beans from coffee farms to processed coffee in markets. 6 | 7 | #### Problems in Existing System 8 | --- 9 | 10 | - Currently Coffee trade mostly relies on fax machines and emails to send and recieve contracts across the globe, resulting into slower and error prone paper work. 11 | 12 | - Blockchain can solve this by providing immutable and verifiable data sources 13 | 14 | 15 | 16 | 17 | #### What we are providing? 18 | --- 19 | 20 | - We have implemented smart contract addressing the issue of storing critical data necessary at different stages of supplychain and making it verifiable by all stakeholders in supplychain. 21 | 22 | 23 | #### Application Workflow Diagram 24 | --- 25 | ![](screens/workflow.png) 26 | 27 | #### In this application we have Six stages 28 | --- 29 | 30 | 1. Admin 31 | 2. Farm-Inspector 32 | 3. Harvester 33 | 4. Exporter 34 | 5. Importer 35 | 6. Processor 36 | 37 | **Admin :** Admin creates new batch which is initial stage of coffee batch. 38 | 39 | **Farm-Inspector :** Farm-inspectors are responsible for inspecting coffee farms and updating the information like coffee family, type of seed and fertilizers used for growing coffee. 40 | 41 | **Harvester :** Harvesters conducting plucking, hulling , polishing , grading and sorting activities, further updating the information of crop variety, temperature used and humidity maintained during the process. 42 | 43 | **Exporter :** Exporters are the organization who exports coffee beans throughout the world. Exporter adds quantity, destination address, ship name, ship number , estimated date and time and exporter id. 44 | 45 | **Importer :** Importers imports the coffee from coffee suppliers and updates quantity, ship name, ship number , transporters information, warehouse name, warehouse address and the importer's address. 46 | 47 | **Processor :** Processors are the organizations who processes raw coffee beans by roasting them on particular temperature and humidity and makes it ready for packaging and to sale into markets. Processor adds the information like quantity, temperature , roasting duration , internal batch number , packaging date time, processor name and processor address. 48 | 49 | #### Included Components 50 | --- 51 | - Solidity (Ethereum) 52 | - Metamask (Ethereum wallet) 53 | - Rinkeby test network ( use rinkeby faucet to get ethers on rinkeby network ) 54 | - Infura 55 | - Truffle 56 | - IPFS 57 | - Web3JS 58 | - Apache and PHP 59 | 60 | #### Prerequisites 61 | --- 62 | - Nodejs v9.10 or above 63 | - Truffle v4.1.8 (core: 4.1.8) (http://truffleframework.com/docs/getting_started/installation) 64 | - Solidity v0.4.23 65 | - Metamask (https://metamask.io) /Ganache Wallet 66 | > [Please Note : infura.io provider is used for the demo ] 67 | 68 | #### Deployment Steps: 69 | --- 70 | **Setting up Ethereum Smart Contract:** 71 | 72 | ``` 73 | git clone https://github.com/rwaltzsoftware-org/coffee-supplychain-ethereum 74 | cd coffee-supplychain-ethereum/ 75 | ``` 76 | 77 | **Update truffle.js ** 78 | 79 | ``` 80 | var HDWalletProvider = require("truffle-hdwallet-provider"); 81 | module.exports = 82 | { 83 | networks: 84 | { 85 | development: 86 | { 87 | host: "localhost", 88 | port: 8545, 89 | network_id: "*" // Match any network id 90 | }, 91 | rinkeby: { 92 | provider: function() { 93 | var mnemonic = "steel neither fatigue ...";//put ETH wallet 12 mnemonic code 94 | return new HDWalletProvider(mnemonic, "https://rinkeby.infura.io/8U0AE4DUGSh8lVO3zmma"); 95 | }, 96 | network_id: '4', 97 | from: '0xab0874cb61d.....',/*ETH wallet 12 mnemonic code wallet address*/ 98 | } 99 | } 100 | }; 101 | ``` 102 | 103 | Go to your project folder in terminal then execute : 104 | 105 | ``` 106 | rm -rf build/ 107 | truffle compile 108 | npm install truffle-hdwallet-provider 109 | truffle migrate --network rinkeby reset 110 | ``` 111 | **Please note:** 112 | 1. After successfully deployment you will get response in bash terminal like below 113 | ``` 114 | Running migration: 1_initial_migration.js 115 | Deploying Migrations... 116 | ... 0x8be4cb8e9c1be61bb83f2661bb8e8a4fefc31433b68137f88a7088a0bb0cccda 117 | Migrations: 0xd0fc5980df528878573d97e91a11b4196b060174 118 | Saving successful migration to network... 119 | ... 0x68483eb11712987b190469033e3b12e04bbe960ffbdbfd508eb7618f91ca7dd6 120 | Saving artifacts... 121 | Running migration: 2_deploy_contracts.js 122 | Deploying SupplyChainStorage... 123 | ... 0x42bd453f05e530d312c6140a848aa111d08e2edb8ec96bd380e78d1fd0ebc444 124 | SupplyChainStorage: 0xe544a8f280e4cb111589f935c483cafb1c6044d0 125 | Deploying SupplyChainUser... 126 | Deploying CoffeeSupplyChain... 127 | ... 0x928fc9e0a4a0c82c0699c8e76247e15af4da9ba7c855735f5db9c8a9d9368575 128 | ... 0x7d47e86f465584e34db27845d7b8ea6f161ea52566fd92426bdff7e1eb1f6789 129 | SupplyChainUser: 0x03f72d93e07428dbfbdff8f54676c19dd4421e2b 130 | CoffeeSupplyChain: 0x668167b434907e2e212cb7cb7d496159c90b41a4 131 | ... 0x692205fd39eb4b96184410d2db4b71535ba5813dee16d96d8345de509b811745 132 | ... 0xd66046eac97c2bedaef7dc63bd88b4a42eec15dcd4d9c4042db7af332c0fda1c 133 | Saving successful migration to network... 134 | ... 0x1e8684bad65ef2b1b64020eff109984a62099083828c6267970a586096cfa03f 135 | Saving artifacts... 136 | 137 | ``` 138 | - From above responce copy address of SupplyChainStorage, SupplyChainUser, CoffeeSupplyChain 139 | - This 3 address we need to paste in [coffee-supplychain-ui/js/app/app.js] file 140 | like below 141 | ``` 142 | var globIcoAddress = { 143 | 'CoffeeMain': "0x668167b434907e2e212cb7cb7d496159c90b41a4", 144 | 'CoffeeUser': "0x03f72d93e07428dbfbdff8f54676c19dd4421e2b", 145 | 'Storage': "0xe544a8f280e4cb111589f935c483cafb1c6044d0" 146 | }; 147 | ``` 148 | --- 149 | **Setting up UI:** 150 | 151 | - Navigate to Apache Document Root in terminal 152 | ``` 153 | git clone https://github.com/rwaltzsoftware-org/coffee-supplychain-ui 154 | cd coffee-supplychain-ui/ 155 | ``` 156 | **For Our Online User Panel Demo:** 157 | 158 | - Open http://coffee-supplychain.rwaltzsoftware.com/user.php 159 | 160 | **For Our Online Admin Panel Demo:** 161 | 162 | - Open http://coffee-supplychain.rwaltzsoftware.com/admin.php 163 | 164 | **Please note:** 165 | 166 | Admin Panel can be only accessed address that deployed the contracts 167 | 168 | 169 | 170 | #### Development Screen's 171 | --- 172 | #### Login Page 173 | --- 174 | ![](screens/login.png) 175 | 176 | - Get MetaMask - You can go for this option if you don't have metamask wallet in your chrome or firefox browser and create your own ethereum wallet 177 | - Log in - You can login to user or admin 178 | 179 | #### Admin Dashboard 180 | --- 181 | ![](screens/admin.png) 182 | 183 | ##### Admin Dashboard Displays 184 | - Total Number of Users 185 | - Total Roles 186 | - Total Batches 187 | - Batches Overview 188 | - Your Address 189 | - Storage Contract Address 190 | - Coffee Supply Chain Contract Address 191 | - List of User Roles 192 | - List of all Users in Coffee Supply Chain 193 | - In admin dashboard you will be able to find out total users registered, total number of roles and total coffee batches created. 194 | - In batches overview section you will be able to find out the progress of each batch. 195 | - By clicking on button Create Batch , admin will be able to create new batch of coffee beans. 196 | - In below section of batches overview you can see your address ( admin wallet address), storage contract address, coffee supply chain contract address and user contract address. 197 | - Below all these addresses, on left side you can find out all the roles available in coffee supply chain and their slugs, on the right side you will find out all users list and their details. 198 | - Using Create User button you can add new user into coffee supply chain. 199 | 200 | #### Admin Activities 201 | --- 202 | ##### Create user 203 | ![](screens/create-user.png) 204 | 205 | - Only admin can add new user in coffee supply chain 206 | - In the Add User form admin have to provide basic information of user like User Wallet Address, Username, User Contact Number, Role of User , User Status means the user is activated or deactivated. 207 | - User can play his role and update information only if he is have activated status. 208 | - Admin also can provide profile image of user and after submitting form successfully. 209 | - Admin can find out the newly added user in Users List on Admin dashboard. 210 | 211 | ##### Create New Batch 212 | ![](screens/create-batch.png) 213 | 214 | - To add new coffee beans batch, you can use create batch button in batches overview section in admin dashboard. 215 | - Here you have to provide basic information of batch like Farmer Registration Number , Farmer’s Name, Farmer’s Address, Exporter Name and Importer Name. 216 | - By submitting Add Batch form you create new batch which can be updated by other roles later. 217 | - You can find out the details of particular batch in Actions column by pressing on eye icon ( view-batch page ) 218 | 219 | ##### Batch Overview 220 | ![](screens/admin1.png) 221 | 222 | - Get all coffee batch information in batch overview. We get the in at what stage the batch is processing.You can find out progress of batch using eye icon ( view batch page). 223 | - By clicking on the read arrow at the end of batch id, admin can find out the transaction details of that particular batch. 224 | - Similarly admin can also scan QR-code to find out the transaction details of batch. 225 | - Coffee Beans Batch States 226 | - --- Processing : when the stage is in process 227 | - --- completed : when the stage is completed by respective roles 228 | - --- Not Available : Batch is not reached upto this stage 229 | 230 | ##### Batch Details 231 | ###### Batch all process completed 232 | ![](screens/Batch-Details-complited.png) 233 | 234 | ###### Batch work in progress 235 | ![](screens/coffeeSupplychain-inprogress.png) 236 | 237 | - In View Batch Page,/ admin will be able to see the progressive information of coffee batch. 238 | - Here we can get all details of each stage and also the name and address of user who updated the particular stage. 239 | --- 240 | 241 | #### User Dashboard 242 | --- 243 | ![](screens/user.png) 244 | 245 | #### User Activities 246 | --- 247 | ##### Update User Profile 248 | ![](screens/user-update-user.png) 249 | 250 | - To update , user profile you can use Update Profile form where you have to fill the information of user like full name of user, his / her contact number and profile image of user. 251 | - In this form role of user and user status can only be modified by admin, user can not edit this information. 252 | 253 | ###### Batch Updation by Farm-inspector 254 | ![](screens/perform-farm-inspection.png) 255 | 256 | - To submit the farm inspection information, user’s having role of Farm inspector will be able to see the update button in batch overview. 257 | - By pressing on update button farm inspector can update information by providing Type of Seed, Coffee Family and Fertilizer Used. 258 | - After successful submit of farm inspectors information batch progress to next step which is harvesting. 259 | 260 | ###### Batch Updation by Harvester 261 | ![](screens/perform-harvesting.png) 262 | 263 | - Harvester grows coffee beans and after complete nourishing of coffee beans harvester makes the bean ready to export by updating Coffee Variety, Temperature and humidity to blockchain. 264 | 265 | ###### Batch Updation by Exporter 266 | ![](screens/perform-exporting.png) 267 | 268 | - Exporters sends the raw coffee beans for further process on beans as per demands and they update their own information to blockchain. 269 | - Once the coffee beans are ready to export, Users having role of Exporters updates the information of Exporting. 270 | - It includes quantity, destination address, ship name, ship number , estimated datetime and exporter id. 271 | - By pressing submit button on the form, exporting information gets stored on blockchain. 272 | 273 | ###### Batch Updation by Importer 274 | ![](screens/perform-importing.png) 275 | 276 | - Warehouses and Organizations who process on raw beans imports the raw coffee beans. While importing coffee beans they have to update their information on blockchain. 277 | - Information of Quantity, Ship Name, Ship Number, Transporter Information, Warehouse Name , Warehouse Address and Importer’s Id Number. 278 | - After importing coffee beans, it goes for processing stage. 279 | 280 | ###### Batch Updation by Processor 281 | ![](screens/perform-processing.png) 282 | 283 | - At last the Processors have to update the processing information like roasting temperature of coffee and get issued the quality certificate, coffee gets ready to sale out in markets. 284 | - Processing have to fill the information of quantity, temperature, time for roasting, internal batch number, packaging date, processor name and address of processor. 285 | - And this is how the Coffee Supply Chain completes for one batch. 286 | 287 | --- 288 | 289 | In this way, we can track the progress of coffee bean after each stage in blockchain. 290 | 291 | The stages which are yet not updated in blockchain are denoted using cross sign and the stages which are completed are denoted by right tick sign. 292 | 293 | You can also find out the name, address and contact information of user who updated the particular stage in coffee supply chain. 294 | 295 | --- 296 | ##### References: 297 | 298 | Journey of Coffee - Blockchain Supply Chain - Provenance to Consumption: https://www.youtube.com/watch?v=YOr9A_TygBk 299 | 300 | --- 301 | ##### Video Links: 302 | 303 | Introduction of Coffee Supply Chain : https://www.youtube.com/watch?v=t_MA40AZFVA&t=19s 304 | 305 | Walk Through of Coffee Supply Chain Demo : https://www.youtube.com/watch?v=ksK9iv13_W4&t=54s 306 | 307 | --- 308 | ##### Todo: 309 | 310 | - Truffle Tests -------------------------------------------------------------------------------- /contracts/SupplyChainStorage.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./SupplyChainStorageOwnable.sol"; 4 | 5 | contract SupplyChainStorage is SupplyChainStorageOwnable { 6 | 7 | address public lastAccess; 8 | constructor() public { 9 | authorizedCaller[msg.sender] = 1; 10 | emit AuthorizedCaller(msg.sender); 11 | } 12 | 13 | /* Events */ 14 | event AuthorizedCaller(address caller); 15 | event DeAuthorizedCaller(address caller); 16 | 17 | /* Modifiers */ 18 | 19 | modifier onlyAuthCaller(){ 20 | lastAccess = msg.sender; 21 | require(authorizedCaller[msg.sender] == 1); 22 | _; 23 | } 24 | 25 | /* User Related */ 26 | struct user { 27 | string name; 28 | string contactNo; 29 | bool isActive; 30 | string profileHash; 31 | } 32 | 33 | mapping(address => user) userDetails; 34 | mapping(address => string) userRole; 35 | 36 | /* Caller Mapping */ 37 | mapping(address => uint8) authorizedCaller; 38 | 39 | /* authorize caller */ 40 | function authorizeCaller(address _caller) public onlyOwner returns(bool) 41 | { 42 | authorizedCaller[_caller] = 1; 43 | emit AuthorizedCaller(_caller); 44 | return true; 45 | } 46 | 47 | /* deauthorize caller */ 48 | function deAuthorizeCaller(address _caller) public onlyOwner returns(bool) 49 | { 50 | authorizedCaller[_caller] = 0; 51 | emit DeAuthorizedCaller(_caller); 52 | return true; 53 | } 54 | 55 | /*User Roles 56 | SUPER_ADMIN, 57 | FARM_INSPECTION, 58 | HARVESTER, 59 | EXPORTER, 60 | IMPORTER, 61 | PROCESSOR 62 | */ 63 | 64 | /* Process Related */ 65 | struct basicDetails { 66 | string registrationNo; 67 | string farmerName; 68 | string farmAddress; 69 | string exporterName; 70 | string importerName; 71 | 72 | } 73 | 74 | struct farmInspector { 75 | string coffeeFamily; 76 | string typeOfSeed; 77 | string fertilizerUsed; 78 | } 79 | 80 | struct harvester { 81 | string cropVariety; 82 | string temperatureUsed; 83 | string humidity; 84 | } 85 | 86 | struct exporter { 87 | string destinationAddress; 88 | string shipName; 89 | string shipNo; 90 | uint256 quantity; 91 | uint256 departureDateTime; 92 | uint256 estimateDateTime; 93 | uint256 plantNo; 94 | uint256 exporterId; 95 | } 96 | 97 | struct importer { 98 | uint256 quantity; 99 | uint256 arrivalDateTime; 100 | uint256 importerId; 101 | string shipName; 102 | string shipNo; 103 | string transportInfo; 104 | string warehouseName; 105 | string warehouseAddress; 106 | } 107 | 108 | struct processor { 109 | uint256 quantity; 110 | uint256 rostingDuration; 111 | uint256 packageDateTime; 112 | string temperature; 113 | string internalBatchNo; 114 | string processorName; 115 | string processorAddress; 116 | } 117 | 118 | mapping (address => basicDetails) batchBasicDetails; 119 | mapping (address => farmInspector) batchFarmInspector; 120 | mapping (address => harvester) batchHarvester; 121 | mapping (address => exporter) batchExporter; 122 | mapping (address => importer) batchImporter; 123 | mapping (address => processor) batchProcessor; 124 | mapping (address => string) nextAction; 125 | 126 | /*Initialize struct pointer*/ 127 | user userDetail; 128 | basicDetails basicDetailsData; 129 | farmInspector farmInspectorData; 130 | harvester harvesterData; 131 | exporter exporterData; 132 | importer importerData; 133 | processor processorData; 134 | 135 | 136 | 137 | /* Get User Role */ 138 | function getUserRole(address _userAddress) public onlyAuthCaller view returns(string) 139 | { 140 | return userRole[_userAddress]; 141 | } 142 | 143 | /* Get Next Action */ 144 | function getNextAction(address _batchNo) public onlyAuthCaller view returns(string) 145 | { 146 | return nextAction[_batchNo]; 147 | } 148 | 149 | /*set user details*/ 150 | function setUser(address _userAddress, 151 | string _name, 152 | string _contactNo, 153 | string _role, 154 | bool _isActive, 155 | string _profileHash) public onlyAuthCaller returns(bool){ 156 | 157 | /*store data into struct*/ 158 | userDetail.name = _name; 159 | userDetail.contactNo = _contactNo; 160 | userDetail.isActive = _isActive; 161 | userDetail.profileHash = _profileHash; 162 | 163 | /*store data into mapping*/ 164 | userDetails[_userAddress] = userDetail; 165 | userRole[_userAddress] = _role; 166 | 167 | return true; 168 | } 169 | 170 | /*get user details*/ 171 | function getUser(address _userAddress) public onlyAuthCaller view returns(string name, 172 | string contactNo, 173 | string role, 174 | bool isActive, 175 | string profileHash 176 | ){ 177 | 178 | /*Getting value from struct*/ 179 | user memory tmpData = userDetails[_userAddress]; 180 | 181 | return (tmpData.name, tmpData.contactNo, userRole[_userAddress], tmpData.isActive, tmpData.profileHash); 182 | } 183 | 184 | /*get batch basicDetails*/ 185 | function getBasicDetails(address _batchNo) public onlyAuthCaller view returns(string registrationNo, 186 | string farmerName, 187 | string farmAddress, 188 | string exporterName, 189 | string importerName) { 190 | 191 | basicDetails memory tmpData = batchBasicDetails[_batchNo]; 192 | 193 | return (tmpData.registrationNo,tmpData.farmerName,tmpData.farmAddress,tmpData.exporterName,tmpData.importerName); 194 | } 195 | 196 | /*set batch basicDetails*/ 197 | function setBasicDetails(string _registrationNo, 198 | string _farmerName, 199 | string _farmAddress, 200 | string _exporterName, 201 | string _importerName 202 | 203 | ) public onlyAuthCaller returns(address) { 204 | 205 | uint tmpData = uint(keccak256(msg.sender, now)); 206 | address batchNo = address(tmpData); 207 | 208 | basicDetailsData.registrationNo = _registrationNo; 209 | basicDetailsData.farmerName = _farmerName; 210 | basicDetailsData.farmAddress = _farmAddress; 211 | basicDetailsData.exporterName = _exporterName; 212 | basicDetailsData.importerName = _importerName; 213 | 214 | batchBasicDetails[batchNo] = basicDetailsData; 215 | 216 | nextAction[batchNo] = 'FARM_INSPECTION'; 217 | 218 | 219 | return batchNo; 220 | } 221 | 222 | /*set farm Inspector data*/ 223 | function setFarmInspectorData(address batchNo, 224 | string _coffeeFamily, 225 | string _typeOfSeed, 226 | string _fertilizerUsed) public onlyAuthCaller returns(bool){ 227 | farmInspectorData.coffeeFamily = _coffeeFamily; 228 | farmInspectorData.typeOfSeed = _typeOfSeed; 229 | farmInspectorData.fertilizerUsed = _fertilizerUsed; 230 | 231 | batchFarmInspector[batchNo] = farmInspectorData; 232 | 233 | nextAction[batchNo] = 'HARVESTER'; 234 | 235 | return true; 236 | } 237 | 238 | 239 | /*get farm inspactor data*/ 240 | function getFarmInspectorData(address batchNo) public onlyAuthCaller view returns (string coffeeFamily,string typeOfSeed,string fertilizerUsed){ 241 | 242 | farmInspector memory tmpData = batchFarmInspector[batchNo]; 243 | return (tmpData.coffeeFamily, tmpData.typeOfSeed, tmpData.fertilizerUsed); 244 | } 245 | 246 | 247 | /*set Harvester data*/ 248 | function setHarvesterData(address batchNo, 249 | string _cropVariety, 250 | string _temperatureUsed, 251 | string _humidity) public onlyAuthCaller returns(bool){ 252 | harvesterData.cropVariety = _cropVariety; 253 | harvesterData.temperatureUsed = _temperatureUsed; 254 | harvesterData.humidity = _humidity; 255 | 256 | batchHarvester[batchNo] = harvesterData; 257 | 258 | nextAction[batchNo] = 'EXPORTER'; 259 | 260 | return true; 261 | } 262 | 263 | /*get farm Harvester data*/ 264 | function getHarvesterData(address batchNo) public onlyAuthCaller view returns(string cropVariety, 265 | string temperatureUsed, 266 | string humidity){ 267 | 268 | harvester memory tmpData = batchHarvester[batchNo]; 269 | return (tmpData.cropVariety, tmpData.temperatureUsed, tmpData.humidity); 270 | } 271 | 272 | /*set Exporter data*/ 273 | function setExporterData(address batchNo, 274 | uint256 _quantity, 275 | string _destinationAddress, 276 | string _shipName, 277 | string _shipNo, 278 | uint256 _estimateDateTime, 279 | uint256 _exporterId) public onlyAuthCaller returns(bool){ 280 | 281 | exporterData.quantity = _quantity; 282 | exporterData.destinationAddress = _destinationAddress; 283 | exporterData.shipName = _shipName; 284 | exporterData.shipNo = _shipNo; 285 | exporterData.departureDateTime = now; 286 | exporterData.estimateDateTime = _estimateDateTime; 287 | exporterData.exporterId = _exporterId; 288 | 289 | batchExporter[batchNo] = exporterData; 290 | 291 | nextAction[batchNo] = 'IMPORTER'; 292 | 293 | return true; 294 | } 295 | 296 | /*get Exporter data*/ 297 | function getExporterData(address batchNo) public onlyAuthCaller view returns(uint256 quantity, 298 | string destinationAddress, 299 | string shipName, 300 | string shipNo, 301 | uint256 departureDateTime, 302 | uint256 estimateDateTime, 303 | uint256 exporterId){ 304 | 305 | 306 | exporter memory tmpData = batchExporter[batchNo]; 307 | 308 | 309 | return (tmpData.quantity, 310 | tmpData.destinationAddress, 311 | tmpData.shipName, 312 | tmpData.shipNo, 313 | tmpData.departureDateTime, 314 | tmpData.estimateDateTime, 315 | tmpData.exporterId); 316 | 317 | 318 | } 319 | 320 | 321 | /*set Importer data*/ 322 | function setImporterData(address batchNo, 323 | uint256 _quantity, 324 | string _shipName, 325 | string _shipNo, 326 | string _transportInfo, 327 | string _warehouseName, 328 | string _warehouseAddress, 329 | uint256 _importerId) public onlyAuthCaller returns(bool){ 330 | 331 | importerData.quantity = _quantity; 332 | importerData.shipName = _shipName; 333 | importerData.shipNo = _shipNo; 334 | importerData.arrivalDateTime = now; 335 | importerData.transportInfo = _transportInfo; 336 | importerData.warehouseName = _warehouseName; 337 | importerData.warehouseAddress = _warehouseAddress; 338 | importerData.importerId = _importerId; 339 | 340 | batchImporter[batchNo] = importerData; 341 | 342 | nextAction[batchNo] = 'PROCESSOR'; 343 | 344 | return true; 345 | } 346 | 347 | /*get Importer data*/ 348 | function getImporterData(address batchNo) public onlyAuthCaller view returns(uint256 quantity, 349 | string shipName, 350 | string shipNo, 351 | uint256 arrivalDateTime, 352 | string transportInfo, 353 | string warehouseName, 354 | string warehouseAddress, 355 | uint256 importerId){ 356 | 357 | importer memory tmpData = batchImporter[batchNo]; 358 | 359 | 360 | return (tmpData.quantity, 361 | tmpData.shipName, 362 | tmpData.shipNo, 363 | tmpData.arrivalDateTime, 364 | tmpData.transportInfo, 365 | tmpData.warehouseName, 366 | tmpData.warehouseAddress, 367 | tmpData.importerId); 368 | 369 | 370 | } 371 | 372 | /*set Proccessor data*/ 373 | function setProcessorData(address batchNo, 374 | uint256 _quantity, 375 | string _temperature, 376 | uint256 _rostingDuration, 377 | string _internalBatchNo, 378 | uint256 _packageDateTime, 379 | string _processorName, 380 | string _processorAddress) public onlyAuthCaller returns(bool){ 381 | 382 | 383 | processorData.quantity = _quantity; 384 | processorData.temperature = _temperature; 385 | processorData.rostingDuration = _rostingDuration; 386 | processorData.internalBatchNo = _internalBatchNo; 387 | processorData.packageDateTime = _packageDateTime; 388 | processorData.processorName = _processorName; 389 | processorData.processorAddress = _processorAddress; 390 | 391 | batchProcessor[batchNo] = processorData; 392 | 393 | nextAction[batchNo] = 'DONE'; 394 | 395 | return true; 396 | } 397 | 398 | 399 | /*get Processor data*/ 400 | function getProcessorData( address batchNo) public onlyAuthCaller view returns( 401 | uint256 quantity, 402 | string temperature, 403 | uint256 rostingDuration, 404 | string internalBatchNo, 405 | uint256 packageDateTime, 406 | string processorName, 407 | string processorAddress){ 408 | 409 | processor memory tmpData = batchProcessor[batchNo]; 410 | 411 | 412 | return ( 413 | tmpData.quantity, 414 | tmpData.temperature, 415 | tmpData.rostingDuration, 416 | tmpData.internalBatchNo, 417 | tmpData.packageDateTime, 418 | tmpData.processorName, 419 | tmpData.processorAddress); 420 | 421 | 422 | } 423 | 424 | } 425 | -------------------------------------------------------------------------------- /test/coffee_supply_chain.js: -------------------------------------------------------------------------------- 1 | 2 | var CoffeeSupplyChain = artifacts.require("../contracts/CoffeeSupplyChain.sol"); 3 | var SupplyChainUser = artifacts.require("../contracts/SupplyChainUser.sol"); 4 | var SupplyChainStorage = artifacts.require("../contracts/SupplyChainStorage.sol"); 5 | 6 | const assert = require('chai').assert; 7 | 8 | contract('CoffeeSupplyChain', function(accounts) { 9 | 10 | const authorizedCaller = accounts[0]; 11 | const farmInspector = accounts[1]; 12 | const harvestor = accounts[2]; 13 | const exporter = accounts[3]; 14 | const importer = accounts[4]; 15 | const processor = accounts[5]; 16 | 17 | beforeEach(async() => { 18 | 19 | this.supplyChainStorage = await SupplyChainStorage.new({from: authorizedCaller}); 20 | 21 | this.coffeeSupplyChain = await CoffeeSupplyChain.new(this.supplyChainStorage.address,{from: authorizedCaller}); 22 | this.supplyChainUser = await SupplyChainUser.new(this.supplyChainStorage.address,{from: authorizedCaller}); 23 | 24 | await this.supplyChainStorage.authorizeCaller(this.coffeeSupplyChain.address,{from: authorizedCaller}); 25 | await this.supplyChainStorage.authorizeCaller(this.supplyChainUser.address,{from: authorizedCaller}); 26 | }); 27 | 28 | async function prepareFarmInspector(contract) 29 | { 30 | var _name = "Alice"; 31 | var _contactNo = "8986587989"; 32 | var _role = "FARM_INSPECTION"; 33 | var _isActive = true; 34 | var _profileHash = "Sample Hash"; 35 | 36 | return await contract 37 | .updateUserForAdmin(farmInspector, 38 | _name, 39 | _contactNo, 40 | _role, 41 | _isActive, 42 | _profileHash, 43 | {from:authorizedCaller}); 44 | } 45 | 46 | async function addFarmBasicDetails(contract) 47 | { 48 | var _registrationNo = "123456789"; 49 | var _farmerName = "Ramu Kaka"; 50 | var _farmAddress = "Nashik"; 51 | var _exporterName = "Rudra Logistics"; 52 | var _importerName = "Boulders Logistics"; 53 | 54 | return await contract 55 | .addBasicDetails( 56 | _registrationNo, 57 | _farmerName, 58 | _farmAddress, 59 | _exporterName, 60 | _importerName,{from:authorizedCaller}); 61 | } 62 | 63 | async function updateFarmInspectorData(contract,batchNo) 64 | { 65 | var _coffeeFamily = "Rubiaceae"; 66 | var _typeOfSeed = "Coffee Arabica"; 67 | var _fertilizerUsed = "Organic"; 68 | 69 | return await contract 70 | .updateFarmInspectorData( 71 | batchNo, 72 | _coffeeFamily, 73 | _typeOfSeed, 74 | _fertilizerUsed,{from:farmInspector}); 75 | } 76 | describe("Cultivation Activities",() => { 77 | 78 | var batchNo = false; 79 | 80 | it("should add cultivation basic details",async() => { 81 | 82 | /********************* Basic Details Section ***********/ 83 | 84 | /* Set Basic Details */ 85 | 86 | const { logs } = addFarmBasicDetails(this.coffeeSupplyChain); 87 | 88 | /* Check if Event Exists */ 89 | const event = logs.find(e => e.event === 'PerformCultivation'); 90 | assert.exists(event,"PerformCultivation event does not exists"); 91 | 92 | batchNo = event.args.batchNo; 93 | 94 | }); 95 | 96 | it("should get cultivation basic details",async() => { 97 | 98 | /* Set Basic Details */ 99 | 100 | const { logs } = addFarmBasicDetails(this.coffeeSupplyChain); 101 | 102 | const event = logs.find(e => e.event === 'PerformCultivation'); 103 | batchNo = event.args.batchNo; 104 | 105 | const activityData = await this.coffeeSupplyChain 106 | .getBasicDetails(batchNo,{from:authorizedCaller}); 107 | 108 | assert.equal(activityData[0],_registrationNo,"Registration No Check:"); 109 | assert.equal(activityData[1],_farmerName,"Farmer Name Check:"); 110 | assert.equal(activityData[2],_farmAddress,"Farmer Address Check:"); 111 | assert.equal(activityData[3],_exporterName,"Exporter Check:"); 112 | assert.equal(activityData[4],_importerName,"Importer Check:"); 113 | }); 114 | 115 | it("should update farm inspection details",async() => { 116 | 117 | /* Prepare Farm Inspector */ 118 | await prepareFarmInspector(this.supplyChainUser); 119 | 120 | /* Set Basic Details */ 121 | 122 | var { logs } = await addFarmBasicDetails(this.coffeeSupplyChain); 123 | 124 | const basicDetailsEvent = logs.find(e => e.event === 'PerformCultivation'); 125 | batchNo = basicDetailsEvent.args.batchNo; 126 | 127 | /* Update Farm Inspector Data */ 128 | var { logs } = await updateFarmInspectorData(this.coffeeSupplyChain,batchNo); 129 | 130 | /* Check if Event Exists */ 131 | const farmInspectionEvent = logs.find(e => e.event === 'DoneInspection'); 132 | assert.exists(farmInspectionEvent,"DoneInspection event does not exists"); 133 | 134 | }); 135 | 136 | it("should get farm inspection details",async() => { 137 | 138 | /* Add User with FARM_INSPECTION Role */ 139 | 140 | var _name = "Alice"; 141 | var _contactNo = "8986587989"; 142 | var _role = "FARM_INSPECTION"; 143 | var _isActive = true; 144 | var _profileHash = "Sample Hash"; 145 | 146 | await this.supplyChainUser 147 | .updateUserForAdmin(farmInspector, 148 | _name, 149 | _contactNo, 150 | _role, 151 | _isActive, 152 | _profileHash, 153 | {from:authorizedCaller}); 154 | 155 | /* Set Basic Details */ 156 | 157 | var _registrationNo = "123456789"; 158 | var _farmerName = "Ramu Kaka"; 159 | var _farmAddress = "Nashik"; 160 | var _exporterName = "Rudra Logistics"; 161 | var _importerName = "Boulders Logistics"; 162 | 163 | var { logs } = await this.coffeeSupplyChain 164 | .addBasicDetails( 165 | _registrationNo, 166 | _farmerName, 167 | _farmAddress, 168 | _exporterName, 169 | _importerName,{from:authorizedCaller}); 170 | 171 | 172 | const basicDetailsEvent = logs.find(e => e.event === 'PerformCultivation'); 173 | batchNo = basicDetailsEvent.args.batchNo; 174 | 175 | 176 | 177 | /* Update Farm Inspection */ 178 | 179 | var _coffeeFamily = "Rubiaceae"; 180 | var _typeOfSeed = "Coffee Arabica"; 181 | var _fertilizerUsed = "Organic"; 182 | 183 | 184 | 185 | var { logs } = await this.coffeeSupplyChain 186 | .updateFarmInspectorData( 187 | batchNo, 188 | _coffeeFamily, 189 | _typeOfSeed, 190 | _fertilizerUsed,{from:farmInspector}); 191 | 192 | 193 | /* Check if Event Exists */ 194 | const farmInspectionEvent = logs.find(e => e.event === 'DoneInspection'); 195 | 196 | batchNo = farmInspectionEvent.args.batchNo; 197 | 198 | const activityData = await this.coffeeSupplyChain 199 | .getFarmInspectorData(batchNo,{from:farmInspector}); 200 | 201 | assert.equal(activityData[0],_coffeeFamily,"Coffee Family Check:"); 202 | assert.equal(activityData[1],_typeOfSeed,"Type of Seed Check:"); 203 | assert.equal(activityData[2],_fertilizerUsed,"Fertilizer Check:"); 204 | }); 205 | 206 | 207 | it("should update harvest details",async() => { 208 | 209 | /* Add User with FARM_INSPECTION Role */ 210 | 211 | var _name = "Alice"; 212 | var _contactNo = "8986587989"; 213 | var _role = "FARM_INSPECTION"; 214 | var _isActive = true; 215 | var _profileHash = "Sample Hash"; 216 | 217 | await this.supplyChainUser 218 | .updateUserForAdmin(farmInspector, 219 | _name, 220 | _contactNo, 221 | _role, 222 | _isActive, 223 | _profileHash, 224 | {from:authorizedCaller}); 225 | 226 | /* Add User with HARVESTER Role */ 227 | 228 | var _name = "Harry"; 229 | var _contactNo = "83236587989"; 230 | var _role = "HARVESTER"; 231 | var _isActive = true; 232 | var _profileHash = "Sample Hash"; 233 | 234 | await this.supplyChainUser 235 | .updateUserForAdmin(harvestor, 236 | _name, 237 | _contactNo, 238 | _role, 239 | _isActive, 240 | _profileHash, 241 | {from:authorizedCaller}); 242 | 243 | 244 | /* Set Basic Details */ 245 | 246 | var _registrationNo = "123456789"; 247 | var _farmerName = "Ramu Kaka"; 248 | var _farmAddress = "Nashik"; 249 | var _exporterName = "Rudra Logistics"; 250 | var _importerName = "Boulders Logistics"; 251 | 252 | var { logs } = await this.coffeeSupplyChain 253 | .addBasicDetails( 254 | _registrationNo, 255 | _farmerName, 256 | _farmAddress, 257 | _exporterName, 258 | _importerName,{from:authorizedCaller}); 259 | 260 | 261 | const basicDetailsEvent = logs.find(e => e.event === 'PerformCultivation'); 262 | batchNo = basicDetailsEvent.args.batchNo; 263 | 264 | 265 | 266 | /* Update Farm Inspection */ 267 | 268 | var _coffeeFamily = "Rubiaceae"; 269 | var _typeOfSeed = "Coffee Arabica"; 270 | var _fertilizerUsed = "Organic"; 271 | 272 | 273 | 274 | await this.coffeeSupplyChain 275 | .updateFarmInspectorData( 276 | batchNo, 277 | _coffeeFamily, 278 | _typeOfSeed, 279 | _fertilizerUsed,{from:farmInspector}); 280 | 281 | 282 | /* Update Harvestor */ 283 | var _cropVariety = "Arusha"; 284 | var _temperatureUsed = "50 fahrenheit"; 285 | var _humidity = "60"; 286 | 287 | var { logs } = await this.coffeeSupplyChain 288 | .updateHarvesterData( 289 | batchNo, 290 | _cropVariety, 291 | _temperatureUsed, 292 | _humidity,{from:harvestor}); 293 | 294 | 295 | /* Check if Event Exists */ 296 | const harvestEvent = logs.find(e => e.event === 'DoneHarvesting'); 297 | assert.exists(harvestEvent,"DoneHarvesting event does not exists"); 298 | 299 | }); 300 | 301 | 302 | it("should get harvest details",async() => { 303 | 304 | /* Add User with FARM_INSPECTION Role */ 305 | 306 | var _name = "Alice"; 307 | var _contactNo = "8986587989"; 308 | var _role = "FARM_INSPECTION"; 309 | var _isActive = true; 310 | var _profileHash = "Sample Hash"; 311 | 312 | await this.supplyChainUser 313 | .updateUserForAdmin(farmInspector, 314 | _name, 315 | _contactNo, 316 | _role, 317 | _isActive, 318 | _profileHash, 319 | {from:authorizedCaller}); 320 | 321 | /* Add User with HARVESTER Role */ 322 | 323 | var _name = "Harry"; 324 | var _contactNo = "83236587989"; 325 | var _role = "HARVESTER"; 326 | var _isActive = true; 327 | var _profileHash = "Sample Hash"; 328 | 329 | await this.supplyChainUser 330 | .updateUserForAdmin(harvestor, 331 | _name, 332 | _contactNo, 333 | _role, 334 | _isActive, 335 | _profileHash, 336 | {from:authorizedCaller}); 337 | 338 | 339 | /* Set Basic Details */ 340 | 341 | var _registrationNo = "123456789"; 342 | var _farmerName = "Ramu Kaka"; 343 | var _farmAddress = "Nashik"; 344 | var _exporterName = "Rudra Logistics"; 345 | var _importerName = "Boulders Logistics"; 346 | 347 | var { logs } = await this.coffeeSupplyChain 348 | .addBasicDetails( 349 | _registrationNo, 350 | _farmerName, 351 | _farmAddress, 352 | _exporterName, 353 | _importerName,{from:authorizedCaller}); 354 | 355 | 356 | const basicDetailsEvent = logs.find(e => e.event === 'PerformCultivation'); 357 | batchNo = basicDetailsEvent.args.batchNo; 358 | 359 | 360 | 361 | /* Update Farm Inspection */ 362 | 363 | var _coffeeFamily = "Rubiaceae"; 364 | var _typeOfSeed = "Coffee Arabica"; 365 | var _fertilizerUsed = "Organic"; 366 | 367 | 368 | 369 | await this.coffeeSupplyChain 370 | .updateFarmInspectorData( 371 | batchNo, 372 | _coffeeFamily, 373 | _typeOfSeed, 374 | _fertilizerUsed,{from:farmInspector}); 375 | 376 | 377 | /* Update Harvestor */ 378 | 379 | var _cropVariety = "Arusha"; 380 | var _temperatureUsed = "50 fahrenheit"; 381 | var _humidity = "60"; 382 | 383 | await this.coffeeSupplyChain 384 | .updateHarvesterData( 385 | batchNo, 386 | _cropVariety, 387 | _temperatureUsed, 388 | _humidity,{from:harvestor}); 389 | 390 | 391 | 392 | const activityData = await this.coffeeSupplyChain 393 | .getHarvesterData(batchNo,{from:harvestor}); 394 | 395 | assert.equal(activityData[0],_cropVariety,"Crop Variety Check:"); 396 | assert.equal(activityData[1],_temperatureUsed,"Temperature Used Check:"); 397 | assert.equal(activityData[2],_humidity,"Humidity Check:"); 398 | 399 | }); 400 | 401 | it("should update export details",async() => { 402 | 403 | /* Add User with FARM_INSPECTION Role */ 404 | 405 | var _name = "Alice"; 406 | var _contactNo = "8986587989"; 407 | var _role = "FARM_INSPECTION"; 408 | var _isActive = true; 409 | var _profileHash = "Sample Hash"; 410 | 411 | await this.supplyChainUser 412 | .updateUserForAdmin(farmInspector, 413 | _name, 414 | _contactNo, 415 | _role, 416 | _isActive, 417 | _profileHash, 418 | {from:authorizedCaller}); 419 | 420 | /* Add User with HARVESTER Role */ 421 | 422 | var _name = "Harry"; 423 | var _contactNo = "83236587989"; 424 | var _role = "HARVESTER"; 425 | var _isActive = true; 426 | var _profileHash = "Sample Hash"; 427 | 428 | await this.supplyChainUser 429 | .updateUserForAdmin(harvestor, 430 | _name, 431 | _contactNo, 432 | _role, 433 | _isActive, 434 | _profileHash, 435 | {from:authorizedCaller}); 436 | 437 | 438 | /* Add User with HARVESTER Role */ 439 | 440 | var _name = "Sam"; 441 | var _contactNo = "432423432432"; 442 | var _role = "EXPORTER"; 443 | var _isActive = true; 444 | var _profileHash = "Sample Hash"; 445 | 446 | await this.supplyChainUser 447 | .updateUserForAdmin(exporter, 448 | _name, 449 | _contactNo, 450 | _role, 451 | _isActive, 452 | _profileHash, 453 | {from:authorizedCaller}); 454 | 455 | 456 | /* Set Basic Details */ 457 | 458 | var _registrationNo = "123456789"; 459 | var _farmerName = "Ramu Kaka"; 460 | var _farmAddress = "Nashik"; 461 | var _exporterName = "Rudra Logistics"; 462 | var _importerName = "Boulders Logistics"; 463 | 464 | var { logs } = await this.coffeeSupplyChain 465 | .addBasicDetails( 466 | _registrationNo, 467 | _farmerName, 468 | _farmAddress, 469 | _exporterName, 470 | _importerName,{from:authorizedCaller}); 471 | 472 | 473 | const basicDetailsEvent = logs.find(e => e.event === 'PerformCultivation'); 474 | batchNo = basicDetailsEvent.args.batchNo; 475 | 476 | 477 | 478 | /* Update Farm Inspection */ 479 | 480 | var _coffeeFamily = "Rubiaceae"; 481 | var _typeOfSeed = "Coffee Arabica"; 482 | var _fertilizerUsed = "Organic"; 483 | 484 | 485 | 486 | await this.coffeeSupplyChain 487 | .updateFarmInspectorData( 488 | batchNo, 489 | _coffeeFamily, 490 | _typeOfSeed, 491 | _fertilizerUsed,{from:farmInspector}); 492 | 493 | 494 | /* Update Harvestor */ 495 | var _cropVariety = "Arusha"; 496 | var _temperatureUsed = "50 fahrenheit"; 497 | var _humidity = "60"; 498 | 499 | var { logs } = await this.coffeeSupplyChain 500 | .updateHarvesterData( 501 | batchNo, 502 | _cropVariety, 503 | _temperatureUsed, 504 | _humidity,{from:harvestor}); 505 | 506 | 507 | /* Update Harvestor */ 508 | var _quantity = 1000; 509 | var _destinationAddress = "3998 Southern Avenue, Missouri"; 510 | var _shipName = "Black Pearl"; 511 | var _shipNo = "1337"; 512 | var _estimateDateTime = 1528454742; 513 | var _exporterId = 60; 514 | 515 | var { logs } = await this.coffeeSupplyChain 516 | .updateExporterData( 517 | batchNo, 518 | _quantity, 519 | _destinationAddress, 520 | _shipName, 521 | _shipNo, 522 | _estimateDateTime, 523 | _exporterId,{from:exporter}); 524 | 525 | /* Check if Event Exists */ 526 | const harvestEvent = logs.find(e => e.event === 'DoneExporting'); 527 | assert.exists(harvestEvent,"DoneExporting event does not exists"); 528 | 529 | }); 530 | 531 | it("should get export details",async() => { 532 | 533 | /* Add User with FARM_INSPECTION Role */ 534 | 535 | var _name = "Alice"; 536 | var _contactNo = "8986587989"; 537 | var _role = "FARM_INSPECTION"; 538 | var _isActive = true; 539 | var _profileHash = "Sample Hash"; 540 | 541 | await this.supplyChainUser 542 | .updateUserForAdmin(farmInspector, 543 | _name, 544 | _contactNo, 545 | _role, 546 | _isActive, 547 | _profileHash, 548 | {from:authorizedCaller}); 549 | 550 | /* Add User with HARVESTER Role */ 551 | 552 | var _name = "Harry"; 553 | var _contactNo = "83236587989"; 554 | var _role = "HARVESTER"; 555 | var _isActive = true; 556 | var _profileHash = "Sample Hash"; 557 | 558 | await this.supplyChainUser 559 | .updateUserForAdmin(harvestor, 560 | _name, 561 | _contactNo, 562 | _role, 563 | _isActive, 564 | _profileHash, 565 | {from:authorizedCaller}); 566 | 567 | 568 | /* Add User with HARVESTER Role */ 569 | 570 | var _name = "Sam"; 571 | var _contactNo = "432423432432"; 572 | var _role = "EXPORTER"; 573 | var _isActive = true; 574 | var _profileHash = "Sample Hash"; 575 | 576 | await this.supplyChainUser 577 | .updateUserForAdmin(exporter, 578 | _name, 579 | _contactNo, 580 | _role, 581 | _isActive, 582 | _profileHash, 583 | {from:authorizedCaller}); 584 | 585 | 586 | /* Set Basic Details */ 587 | 588 | var _registrationNo = "123456789"; 589 | var _farmerName = "Ramu Kaka"; 590 | var _farmAddress = "Nashik"; 591 | var _exporterName = "Rudra Logistics"; 592 | var _importerName = "Boulders Logistics"; 593 | 594 | var { logs } = await this.coffeeSupplyChain 595 | .addBasicDetails( 596 | _registrationNo, 597 | _farmerName, 598 | _farmAddress, 599 | _exporterName, 600 | _importerName,{from:authorizedCaller}); 601 | 602 | 603 | const basicDetailsEvent = logs.find(e => e.event === 'PerformCultivation'); 604 | batchNo = basicDetailsEvent.args.batchNo; 605 | 606 | 607 | 608 | /* Update Farm Inspection */ 609 | 610 | var _coffeeFamily = "Rubiaceae"; 611 | var _typeOfSeed = "Coffee Arabica"; 612 | var _fertilizerUsed = "Organic"; 613 | 614 | 615 | 616 | await this.coffeeSupplyChain 617 | .updateFarmInspectorData( 618 | batchNo, 619 | _coffeeFamily, 620 | _typeOfSeed, 621 | _fertilizerUsed,{from:farmInspector}); 622 | 623 | 624 | /* Update Harvestor */ 625 | var _cropVariety = "Arusha"; 626 | var _temperatureUsed = "50 fahrenheit"; 627 | var _humidity = "60"; 628 | 629 | var { logs } = await this.coffeeSupplyChain 630 | .updateHarvesterData( 631 | batchNo, 632 | _cropVariety, 633 | _temperatureUsed, 634 | _humidity,{from:harvestor}); 635 | 636 | 637 | /* Update Exporter */ 638 | var _quantity = 1000; 639 | var _destinationAddress = "3998 Southern Avenue, Missouri"; 640 | var _shipName = "Black Pearl"; 641 | var _shipNo = "1337"; 642 | var _estimateDateTime = 1528454742; 643 | var _exporterId = 60; 644 | 645 | await this.coffeeSupplyChain 646 | .updateExporterData( 647 | batchNo, 648 | _quantity, 649 | _destinationAddress, 650 | _shipName, 651 | _shipNo, 652 | _estimateDateTime, 653 | _exporterId,{from:exporter}); 654 | 655 | 656 | const activityData = await this.coffeeSupplyChain 657 | .getExporterData(batchNo,{from:harvestor}); 658 | 659 | 660 | assert.equal(activityData[0].toNumber(),_quantity,"Quantity Check:"); 661 | assert.equal(activityData[1],_destinationAddress,"Destination Address Check:"); 662 | assert.equal(activityData[2],_shipName,"Ship Name Check:"); 663 | assert.equal(activityData[3],_shipNo,"Ship No Check:"); 664 | assert.isNumber(activityData[4].toNumber(),"Departure Datetime Check:"); 665 | assert.equal(activityData[5].toNumber(),_estimateDateTime,"Estimate Datetime Check:"); 666 | assert.equal(activityData[6].toNumber(),_exporterId,"Exporter Id Check:"); 667 | 668 | }); 669 | 670 | it("should update importer details",async() => { 671 | 672 | /* Add User with FARM_INSPECTION Role */ 673 | 674 | var _name = "Alice"; 675 | var _contactNo = "8986587989"; 676 | var _role = "FARM_INSPECTION"; 677 | var _isActive = true; 678 | var _profileHash = "Sample Hash"; 679 | 680 | await this.supplyChainUser 681 | .updateUserForAdmin(farmInspector, 682 | _name, 683 | _contactNo, 684 | _role, 685 | _isActive, 686 | _profileHash, 687 | {from:authorizedCaller}); 688 | 689 | /* Add User with HARVESTER Role */ 690 | 691 | var _name = "Harry"; 692 | var _contactNo = "83236587989"; 693 | var _role = "HARVESTER"; 694 | var _isActive = true; 695 | var _profileHash = "Sample Hash"; 696 | 697 | await this.supplyChainUser 698 | .updateUserForAdmin(harvestor, 699 | _name, 700 | _contactNo, 701 | _role, 702 | _isActive, 703 | _profileHash, 704 | {from:authorizedCaller}); 705 | 706 | 707 | /* Add User with EXPORTER Role */ 708 | 709 | var _name = "Sam"; 710 | var _contactNo = "432423432432"; 711 | var _role = "EXPORTER"; 712 | var _isActive = true; 713 | var _profileHash = "Sample Hash"; 714 | 715 | await this.supplyChainUser 716 | .updateUserForAdmin(exporter, 717 | _name, 718 | _contactNo, 719 | _role, 720 | _isActive, 721 | _profileHash, 722 | {from:authorizedCaller}); 723 | 724 | 725 | /* Add User with IMPORTER Role */ 726 | 727 | var _name = "Ravi"; 728 | var _contactNo = "3424234353"; 729 | var _role = "IMPORTER"; 730 | var _isActive = true; 731 | var _profileHash = "Sample Hash"; 732 | 733 | await this.supplyChainUser 734 | .updateUserForAdmin(importer, 735 | _name, 736 | _contactNo, 737 | _role, 738 | _isActive, 739 | _profileHash, 740 | {from:authorizedCaller}); 741 | 742 | 743 | /* Set Basic Details */ 744 | 745 | var _registrationNo = "123456789"; 746 | var _farmerName = "Ramu Kaka"; 747 | var _farmAddress = "Nashik"; 748 | var _exporterName = "Rudra Logistics"; 749 | var _importerName = "Boulders Logistics"; 750 | 751 | var { logs } = await this.coffeeSupplyChain 752 | .addBasicDetails( 753 | _registrationNo, 754 | _farmerName, 755 | _farmAddress, 756 | _exporterName, 757 | _importerName,{from:authorizedCaller}); 758 | 759 | 760 | const basicDetailsEvent = logs.find(e => e.event === 'PerformCultivation'); 761 | batchNo = basicDetailsEvent.args.batchNo; 762 | 763 | 764 | 765 | /* Update Farm Inspection */ 766 | 767 | var _coffeeFamily = "Rubiaceae"; 768 | var _typeOfSeed = "Coffee Arabica"; 769 | var _fertilizerUsed = "Organic"; 770 | 771 | 772 | 773 | await this.coffeeSupplyChain 774 | .updateFarmInspectorData( 775 | batchNo, 776 | _coffeeFamily, 777 | _typeOfSeed, 778 | _fertilizerUsed,{from:farmInspector}); 779 | 780 | 781 | /* Update Harvestor */ 782 | var _cropVariety = "Arusha"; 783 | var _temperatureUsed = "50 fahrenheit"; 784 | var _humidity = "60"; 785 | 786 | await this.coffeeSupplyChain 787 | .updateHarvesterData( 788 | batchNo, 789 | _cropVariety, 790 | _temperatureUsed, 791 | _humidity,{from:harvestor}); 792 | 793 | 794 | /* Update Exporter */ 795 | var _quantity = 1000; 796 | var _destinationAddress = "3998 Southern Avenue, Missouri"; 797 | var _shipName = "Black Pearl"; 798 | var _shipNo = "1337"; 799 | var _estimateDateTime = 1528454742; 800 | var _exporterId = 60; 801 | 802 | await this.coffeeSupplyChain 803 | .updateExporterData( 804 | batchNo, 805 | _quantity, 806 | _destinationAddress, 807 | _shipName, 808 | _shipNo, 809 | _estimateDateTime, 810 | _exporterId,{from:exporter}); 811 | 812 | 813 | /* Update Importer */ 814 | var _quantity = 1000; 815 | var _shipName = "Black Pearl"; 816 | var _shipNo = "1337"; 817 | var _transportInfo = "Extra Info"; 818 | var _warehouseName = "ABC"; 819 | var _warehouseAddress = " Southern Avenue, Missouri"; 820 | var _importerId = 45; 821 | 822 | var {logs} = await this.coffeeSupplyChain 823 | .updateImporterData( 824 | batchNo, 825 | _quantity, 826 | _shipName, 827 | _shipNo, 828 | _transportInfo, 829 | _warehouseName, 830 | _warehouseAddress, 831 | _importerId,{from:importer}); 832 | 833 | /* Check if Event Exists */ 834 | const ImportEvent = logs.find(e => e.event === 'DoneImporting'); 835 | assert.exists(ImportEvent,"DoneImporting event does not exists"); 836 | 837 | }); 838 | 839 | it("should get importer details",async() => { 840 | 841 | /* Add User with FARM_INSPECTION Role */ 842 | 843 | var _name = "Alice"; 844 | var _contactNo = "8986587989"; 845 | var _role = "FARM_INSPECTION"; 846 | var _isActive = true; 847 | var _profileHash = "Sample Hash"; 848 | 849 | await this.supplyChainUser 850 | .updateUserForAdmin(farmInspector, 851 | _name, 852 | _contactNo, 853 | _role, 854 | _isActive, 855 | _profileHash, 856 | {from:authorizedCaller}); 857 | 858 | /* Add User with HARVESTER Role */ 859 | 860 | var _name = "Harry"; 861 | var _contactNo = "83236587989"; 862 | var _role = "HARVESTER"; 863 | var _isActive = true; 864 | var _profileHash = "Sample Hash"; 865 | 866 | await this.supplyChainUser 867 | .updateUserForAdmin(harvestor, 868 | _name, 869 | _contactNo, 870 | _role, 871 | _isActive, 872 | _profileHash, 873 | {from:authorizedCaller}); 874 | 875 | 876 | /* Add User with EXPORTER Role */ 877 | 878 | var _name = "Sam"; 879 | var _contactNo = "432423432432"; 880 | var _role = "EXPORTER"; 881 | var _isActive = true; 882 | var _profileHash = "Sample Hash"; 883 | 884 | await this.supplyChainUser 885 | .updateUserForAdmin(exporter, 886 | _name, 887 | _contactNo, 888 | _role, 889 | _isActive, 890 | _profileHash, 891 | {from:authorizedCaller}); 892 | 893 | 894 | /* Add User with IMPORTER Role */ 895 | 896 | var _name = "Ravi"; 897 | var _contactNo = "3424234353"; 898 | var _role = "IMPORTER"; 899 | var _isActive = true; 900 | var _profileHash = "Sample Hash"; 901 | 902 | await this.supplyChainUser 903 | .updateUserForAdmin(importer, 904 | _name, 905 | _contactNo, 906 | _role, 907 | _isActive, 908 | _profileHash, 909 | {from:authorizedCaller}); 910 | 911 | 912 | /* Set Basic Details */ 913 | 914 | var _registrationNo = "123456789"; 915 | var _farmerName = "Ramu Kaka"; 916 | var _farmAddress = "Nashik"; 917 | var _exporterName = "Rudra Logistics"; 918 | var _importerName = "Boulders Logistics"; 919 | 920 | var { logs } = await this.coffeeSupplyChain 921 | .addBasicDetails( 922 | _registrationNo, 923 | _farmerName, 924 | _farmAddress, 925 | _exporterName, 926 | _importerName,{from:authorizedCaller}); 927 | 928 | 929 | const basicDetailsEvent = logs.find(e => e.event === 'PerformCultivation'); 930 | batchNo = basicDetailsEvent.args.batchNo; 931 | 932 | 933 | 934 | /* Update Farm Inspection */ 935 | 936 | var _coffeeFamily = "Rubiaceae"; 937 | var _typeOfSeed = "Coffee Arabica"; 938 | var _fertilizerUsed = "Organic"; 939 | 940 | 941 | 942 | await this.coffeeSupplyChain 943 | .updateFarmInspectorData( 944 | batchNo, 945 | _coffeeFamily, 946 | _typeOfSeed, 947 | _fertilizerUsed,{from:farmInspector}); 948 | 949 | 950 | /* Update Harvestor */ 951 | var _cropVariety = "Arusha"; 952 | var _temperatureUsed = "50 fahrenheit"; 953 | var _humidity = "60"; 954 | 955 | await this.coffeeSupplyChain 956 | .updateHarvesterData( 957 | batchNo, 958 | _cropVariety, 959 | _temperatureUsed, 960 | _humidity,{from:harvestor}); 961 | 962 | 963 | /* Update Exporter */ 964 | var _quantity = 1000; 965 | var _destinationAddress = "3998 Southern Avenue, Missouri"; 966 | var _shipName = "Black Pearl"; 967 | var _shipNo = "1337"; 968 | var _estimateDateTime = 1528454742; 969 | var _exporterId = 60; 970 | 971 | await this.coffeeSupplyChain 972 | .updateExporterData( 973 | batchNo, 974 | _quantity, 975 | _destinationAddress, 976 | _shipName, 977 | _shipNo, 978 | _estimateDateTime, 979 | _exporterId,{from:exporter}); 980 | 981 | 982 | /* Update Importer */ 983 | var _quantity = 1000; 984 | var _shipName = "Black Pearl"; 985 | var _shipNo = "1337"; 986 | var _transportInfo = "Extra Info"; 987 | var _warehouseName = "ABC"; 988 | var _warehouseAddress = " Southern Avenue, Missouri"; 989 | var _importerId = 45; 990 | 991 | await this.coffeeSupplyChain 992 | .updateImporterData( 993 | batchNo, 994 | _quantity, 995 | _shipName, 996 | _shipNo, 997 | _transportInfo, 998 | _warehouseName, 999 | _warehouseAddress, 1000 | _importerId,{from:importer}); 1001 | 1002 | const activityData = await this.coffeeSupplyChain 1003 | .getImporterData(batchNo,{from:importer}); 1004 | 1005 | 1006 | assert.equal(activityData[0].toNumber(),_quantity,"Quantity Check:"); 1007 | assert.equal(activityData[1],_shipName,"Ship Name Check:"); 1008 | assert.equal(activityData[2],_shipNo,"Ship No Check:"); 1009 | assert.isNumber(activityData[3].toNumber(),"Arrival Datetime Check :"); 1010 | assert.equal(activityData[4],_transportInfo,"TransportInfo Check:"); 1011 | assert.equal(activityData[5],_warehouseName,"Warehouse name Check:"); 1012 | assert.equal(activityData[6],_warehouseAddress,"Warehouse Address Check:"); 1013 | assert.equal(activityData[7],_importerId,"Importer Id Check:"); 1014 | 1015 | }); 1016 | 1017 | it("should update processor details",async() => { 1018 | 1019 | /* Add User with FARM_INSPECTION Role */ 1020 | 1021 | var _name = "Alice"; 1022 | var _contactNo = "8986587989"; 1023 | var _role = "FARM_INSPECTION"; 1024 | var _isActive = true; 1025 | var _profileHash = "Sample Hash"; 1026 | 1027 | await this.supplyChainUser 1028 | .updateUserForAdmin(farmInspector, 1029 | _name, 1030 | _contactNo, 1031 | _role, 1032 | _isActive, 1033 | _profileHash, 1034 | {from:authorizedCaller}); 1035 | 1036 | /* Add User with HARVESTER Role */ 1037 | 1038 | var _name = "Harry"; 1039 | var _contactNo = "83236587989"; 1040 | var _role = "HARVESTER"; 1041 | var _isActive = true; 1042 | var _profileHash = "Sample Hash"; 1043 | 1044 | await this.supplyChainUser 1045 | .updateUserForAdmin(harvestor, 1046 | _name, 1047 | _contactNo, 1048 | _role, 1049 | _isActive, 1050 | _profileHash, 1051 | {from:authorizedCaller}); 1052 | 1053 | 1054 | /* Add User with EXPORTER Role */ 1055 | 1056 | var _name = "Sam"; 1057 | var _contactNo = "432423432432"; 1058 | var _role = "EXPORTER"; 1059 | var _isActive = true; 1060 | var _profileHash = "Sample Hash"; 1061 | 1062 | await this.supplyChainUser 1063 | .updateUserForAdmin(exporter, 1064 | _name, 1065 | _contactNo, 1066 | _role, 1067 | _isActive, 1068 | _profileHash, 1069 | {from:authorizedCaller}); 1070 | 1071 | 1072 | /* Add User with IMPORTER Role */ 1073 | 1074 | var _name = "Ravi"; 1075 | var _contactNo = "3424234353"; 1076 | var _role = "IMPORTER"; 1077 | var _isActive = true; 1078 | var _profileHash = "Sample Hash"; 1079 | 1080 | await this.supplyChainUser 1081 | .updateUserForAdmin(importer, 1082 | _name, 1083 | _contactNo, 1084 | _role, 1085 | _isActive, 1086 | _profileHash, 1087 | {from:authorizedCaller}); 1088 | 1089 | /* Add User with PROCESSOR Role */ 1090 | 1091 | var _name = "Jay"; 1092 | var _contactNo = "234234234"; 1093 | var _role = "PROCESSOR"; 1094 | var _isActive = true; 1095 | var _profileHash = "Sample Hash"; 1096 | 1097 | await this.supplyChainUser 1098 | .updateUserForAdmin(processor, 1099 | _name, 1100 | _contactNo, 1101 | _role, 1102 | _isActive, 1103 | _profileHash, 1104 | {from:authorizedCaller}); 1105 | 1106 | /* Set Basic Details */ 1107 | 1108 | var _registrationNo = "123456789"; 1109 | var _farmerName = "Ramu Kaka"; 1110 | var _farmAddress = "Nashik"; 1111 | var _exporterName = "Rudra Logistics"; 1112 | var _importerName = "Boulders Logistics"; 1113 | 1114 | var { logs } = await this.coffeeSupplyChain 1115 | .addBasicDetails( 1116 | _registrationNo, 1117 | _farmerName, 1118 | _farmAddress, 1119 | _exporterName, 1120 | _importerName,{from:authorizedCaller}); 1121 | 1122 | 1123 | const basicDetailsEvent = logs.find(e => e.event === 'PerformCultivation'); 1124 | batchNo = basicDetailsEvent.args.batchNo; 1125 | 1126 | 1127 | 1128 | /* Update Farm Inspection */ 1129 | 1130 | var _coffeeFamily = "Rubiaceae"; 1131 | var _typeOfSeed = "Coffee Arabica"; 1132 | var _fertilizerUsed = "Organic"; 1133 | 1134 | 1135 | 1136 | await this.coffeeSupplyChain 1137 | .updateFarmInspectorData( 1138 | batchNo, 1139 | _coffeeFamily, 1140 | _typeOfSeed, 1141 | _fertilizerUsed,{from:farmInspector}); 1142 | 1143 | 1144 | /* Update Harvestor */ 1145 | var _cropVariety = "Arusha"; 1146 | var _temperatureUsed = "50 fahrenheit"; 1147 | var _humidity = "60"; 1148 | 1149 | await this.coffeeSupplyChain 1150 | .updateHarvesterData( 1151 | batchNo, 1152 | _cropVariety, 1153 | _temperatureUsed, 1154 | _humidity,{from:harvestor}); 1155 | 1156 | 1157 | /* Update Exporter */ 1158 | var _quantity = 1000; 1159 | var _destinationAddress = "3998 Southern Avenue, Missouri"; 1160 | var _shipName = "Black Pearl"; 1161 | var _shipNo = "1337"; 1162 | var _estimateDateTime = 1528454742; 1163 | var _exporterId = 60; 1164 | 1165 | await this.coffeeSupplyChain 1166 | .updateExporterData( 1167 | batchNo, 1168 | _quantity, 1169 | _destinationAddress, 1170 | _shipName, 1171 | _shipNo, 1172 | _estimateDateTime, 1173 | _exporterId,{from:exporter}); 1174 | 1175 | 1176 | /* Update Importer */ 1177 | var _quantity = 1000; 1178 | var _shipName = "Black Pearl"; 1179 | var _shipNo = "1337"; 1180 | var _transportInfo = "Extra Info"; 1181 | var _warehouseName = "ABC"; 1182 | var _warehouseAddress = " Southern Avenue, Missouri"; 1183 | var _importerId = 45; 1184 | 1185 | await this.coffeeSupplyChain 1186 | .updateImporterData( 1187 | batchNo, 1188 | _quantity, 1189 | _shipName, 1190 | _shipNo, 1191 | _transportInfo, 1192 | _warehouseName, 1193 | _warehouseAddress, 1194 | _importerId,{from:importer}); 1195 | 1196 | /* Update Processor */ 1197 | var _quantity = 1000; 1198 | var _temperature = "50 fahrenheit"; 1199 | var _rostingDuration = 60; 1200 | var _internalBatchNo = "BA32323"; 1201 | var _packageDateTime = 1528454742; 1202 | var _processorName = "Starbucks"; 1203 | var _processorAddress = "Southern Avenue, Missouri"; 1204 | 1205 | var {logs} = await this.coffeeSupplyChain 1206 | .updateProcessorData( 1207 | batchNo, 1208 | _quantity, 1209 | _temperature, 1210 | _rostingDuration, 1211 | _internalBatchNo, 1212 | _packageDateTime, 1213 | _processorName, 1214 | _processorAddress,{from:processor}); 1215 | 1216 | /* Check if Event Exists */ 1217 | const ProcessorEvent = logs.find(e => e.event === 'DoneProcessing'); 1218 | assert.exists(ProcessorEvent,"DoneProcessing event does not exists"); 1219 | 1220 | }); 1221 | 1222 | it("should get processor details",async() => { 1223 | 1224 | /* Add User with FARM_INSPECTION Role */ 1225 | 1226 | var _name = "Alice"; 1227 | var _contactNo = "8986587989"; 1228 | var _role = "FARM_INSPECTION"; 1229 | var _isActive = true; 1230 | var _profileHash = "Sample Hash"; 1231 | 1232 | await this.supplyChainUser 1233 | .updateUserForAdmin(farmInspector, 1234 | _name, 1235 | _contactNo, 1236 | _role, 1237 | _isActive, 1238 | _profileHash, 1239 | {from:authorizedCaller}); 1240 | 1241 | /* Add User with HARVESTER Role */ 1242 | 1243 | var _name = "Harry"; 1244 | var _contactNo = "83236587989"; 1245 | var _role = "HARVESTER"; 1246 | var _isActive = true; 1247 | var _profileHash = "Sample Hash"; 1248 | 1249 | await this.supplyChainUser 1250 | .updateUserForAdmin(harvestor, 1251 | _name, 1252 | _contactNo, 1253 | _role, 1254 | _isActive, 1255 | _profileHash, 1256 | {from:authorizedCaller}); 1257 | 1258 | 1259 | /* Add User with EXPORTER Role */ 1260 | 1261 | var _name = "Sam"; 1262 | var _contactNo = "432423432432"; 1263 | var _role = "EXPORTER"; 1264 | var _isActive = true; 1265 | var _profileHash = "Sample Hash"; 1266 | 1267 | await this.supplyChainUser 1268 | .updateUserForAdmin(exporter, 1269 | _name, 1270 | _contactNo, 1271 | _role, 1272 | _isActive, 1273 | _profileHash, 1274 | {from:authorizedCaller}); 1275 | 1276 | 1277 | /* Add User with IMPORTER Role */ 1278 | 1279 | var _name = "Ravi"; 1280 | var _contactNo = "3424234353"; 1281 | var _role = "IMPORTER"; 1282 | var _isActive = true; 1283 | var _profileHash = "Sample Hash"; 1284 | 1285 | await this.supplyChainUser 1286 | .updateUserForAdmin(importer, 1287 | _name, 1288 | _contactNo, 1289 | _role, 1290 | _isActive, 1291 | _profileHash, 1292 | {from:authorizedCaller}); 1293 | 1294 | /* Add User with PROCESSOR Role */ 1295 | 1296 | var _name = "Jay"; 1297 | var _contactNo = "234234234"; 1298 | var _role = "PROCESSOR"; 1299 | var _isActive = true; 1300 | var _profileHash = "Sample Hash"; 1301 | 1302 | await this.supplyChainUser 1303 | .updateUserForAdmin(processor, 1304 | _name, 1305 | _contactNo, 1306 | _role, 1307 | _isActive, 1308 | _profileHash, 1309 | {from:authorizedCaller}); 1310 | 1311 | /* Set Basic Details */ 1312 | 1313 | var _registrationNo = "123456789"; 1314 | var _farmerName = "Ramu Kaka"; 1315 | var _farmAddress = "Nashik"; 1316 | var _exporterName = "Rudra Logistics"; 1317 | var _importerName = "Boulders Logistics"; 1318 | 1319 | var { logs } = await this.coffeeSupplyChain 1320 | .addBasicDetails( 1321 | _registrationNo, 1322 | _farmerName, 1323 | _farmAddress, 1324 | _exporterName, 1325 | _importerName,{from:authorizedCaller}); 1326 | 1327 | 1328 | const basicDetailsEvent = logs.find(e => e.event === 'PerformCultivation'); 1329 | batchNo = basicDetailsEvent.args.batchNo; 1330 | 1331 | 1332 | 1333 | /* Update Farm Inspection */ 1334 | 1335 | var _coffeeFamily = "Rubiaceae"; 1336 | var _typeOfSeed = "Coffee Arabica"; 1337 | var _fertilizerUsed = "Organic"; 1338 | 1339 | 1340 | 1341 | await this.coffeeSupplyChain 1342 | .updateFarmInspectorData( 1343 | batchNo, 1344 | _coffeeFamily, 1345 | _typeOfSeed, 1346 | _fertilizerUsed,{from:farmInspector}); 1347 | 1348 | 1349 | /* Update Harvestor */ 1350 | var _cropVariety = "Arusha"; 1351 | var _temperatureUsed = "50 fahrenheit"; 1352 | var _humidity = "60"; 1353 | 1354 | await this.coffeeSupplyChain 1355 | .updateHarvesterData( 1356 | batchNo, 1357 | _cropVariety, 1358 | _temperatureUsed, 1359 | _humidity,{from:harvestor}); 1360 | 1361 | 1362 | /* Update Exporter */ 1363 | var _quantity = 1000; 1364 | var _destinationAddress = "3998 Southern Avenue, Missouri"; 1365 | var _shipName = "Black Pearl"; 1366 | var _shipNo = "1337"; 1367 | var _estimateDateTime = 1528454742; 1368 | var _exporterId = 60; 1369 | 1370 | await this.coffeeSupplyChain 1371 | .updateExporterData( 1372 | batchNo, 1373 | _quantity, 1374 | _destinationAddress, 1375 | _shipName, 1376 | _shipNo, 1377 | _estimateDateTime, 1378 | _exporterId,{from:exporter}); 1379 | 1380 | 1381 | /* Update Importer */ 1382 | var _quantity = 1000; 1383 | var _shipName = "Black Pearl"; 1384 | var _shipNo = "1337"; 1385 | var _transportInfo = "Extra Info"; 1386 | var _warehouseName = "ABC"; 1387 | var _warehouseAddress = " Southern Avenue, Missouri"; 1388 | var _importerId = 45; 1389 | 1390 | await this.coffeeSupplyChain 1391 | .updateImporterData( 1392 | batchNo, 1393 | _quantity, 1394 | _shipName, 1395 | _shipNo, 1396 | _transportInfo, 1397 | _warehouseName, 1398 | _warehouseAddress, 1399 | _importerId,{from:importer}); 1400 | 1401 | /* Update Processor */ 1402 | var _quantity = 1000; 1403 | var _temperature = "50 fahrenheit"; 1404 | var _rostingDuration = 60; 1405 | var _internalBatchNo = "BA32323"; 1406 | var _packageDateTime = 1528454742; 1407 | var _processorName = "Starbucks"; 1408 | var _processorAddress = "Southern Avenue, Missouri"; 1409 | 1410 | var {logs} = await this.coffeeSupplyChain 1411 | .updateProcessorData( 1412 | batchNo, 1413 | _quantity, 1414 | _temperature, 1415 | _rostingDuration, 1416 | _internalBatchNo, 1417 | _packageDateTime, 1418 | _processorName, 1419 | _processorAddress,{from:processor}); 1420 | 1421 | const activityData = await this.coffeeSupplyChain 1422 | .getProcessorData(batchNo,{from:processor}); 1423 | 1424 | 1425 | assert.equal(activityData[0].toNumber(),_quantity,"Quantity Check:"); 1426 | assert.equal(activityData[1],_temperature,"Temperature Check:"); 1427 | assert.equal(activityData[2].toNumber(),_rostingDuration,"Roasting Duration Check :"); 1428 | assert.equal(activityData[3],_internalBatchNo,"Internal Batch No Check:"); 1429 | assert.equal(activityData[4].toNumber(),_packageDateTime,"Package Datetime Check :"); 1430 | assert.equal(activityData[5],_processorName,"Processor name Check:"); 1431 | assert.equal(activityData[6],_processorAddress,"Processor Address Check:"); 1432 | 1433 | }); 1434 | }); 1435 | 1436 | }); 1437 | 1438 | --------------------------------------------------------------------------------