1"use strict"; 2angular 3 .module("sfmStore") 4 .service("$order", function(APP_CONFIG, $http, $localStorage) { 5 var self = this; 6 this.plusTriggeredByOrder = 0; 7 this.order; 8 9 // We want to check local storage first to see if an order has been initiated already, 10 // if it has grab that order, otherwise start a fresh order. 11 (function() { 12 if ($localStorage.sfmOrder) { 13 self.order = $localStorage.sfmOrder; 14 } else { 15 self.order = { 16 profile: {}, 17 school: {}, 18 payment: { 19 pay_by_check: false 20 }, 21 details: { 22 items: [], 23 coupon: {}, 24 order_status: "STARTED", 25 total: 0, 26 cart_time: new Date() 27 } 28 }; 29 } 30 })(); 31 32 this.clear = function() { 33 self.order = { 34 profile: {}, 35 school: {}, 36 payment: { 37 pay_by_check: false 38 }, 39 details: { 40 items: [], 41 coupon: {}, 42 order_status: "STARTED", 43 total: 0, 44 cart_time: new Date() 45 } 46 }; 47 this.persistOrder(); 48 }; 49 50 this.persistOrder = function() { 51 $localStorage.sfmOrder = this.order; 52 }; 53 54 this.setExtended = function(value) { 55 if (value) { 56 this.order.details.extended = value; 57 } else { 58 this.order.details.extended = false; 59 } 60 this.persistOrder(); 61 }; 62 63 this.getExtended = function() { 64 if (this.order.details.extended) { 65 return this.order.details.extended; 66 } 67 return false; 68 }; 69 70 this.updateProfile = function(profile) { 71 this.order.profile = profile || {}; 72 this.persistOrder(); 73 }; 74 75 this.getProfile = function() { 76 if ( 77 !angular.isUndefined(this.order.profile) && 78 this.order.profile.email 79 ) { 80 return this.order.profile; 81 } 82 return {}; 83 }; 84 85 this.updateSchool = function(school) { 86 if (angular.isUndefined(school)) { 87 school = { 88 School_Name: null, 89 id: null 90 }; 91 } 92 this.order.school = school || {}; 93 this.order.profile.school_name = school.School_Name || ""; 94 this.order.profile.school_id = school.id || ""; 95 this.getTotal(); 96 }; 97 98 this.getSchool = function(field) { 99 if ( 100 !angular.isUndefined(this.order.school) && 101 this.order.school.School_Name 102 ) { 103 return this.order.school; 104 } 105 return false; 106 }; 107 108 // We DO NOT want to store the user's credit card details in local storage. 109 this.updatePayment = function(payment, billing) { 110 this.order.payment = payment || {}; 111 this.order.profile.billing = billing || {}; 112 }; 113 114 this.addOrderItem = function(item) { 115 var retVal = { 116 success: true 117 }; 118 var items = this.order.details.items; 119 120 //If the user is trying to add an insurance or software item make sure there is only one in the cart' 121 if (item.type === "pkg" || item.type === "rnwl" || item.type === "software") { 122 const lookupType = item.type === "software" ? "software" : "pkg"; 123 const productType = item.type === "software" ? "finance manager" : "insurance"; 124 var dupItem = this.getDuplicateItem(lookupType); 125 if (dupItem) { 126 retVal = { 127 success: false, 128 error: 129 "You can only purchase one " + productType + " item at a time. '" + 130 item.title + 131 "' was not added to your cart." 132 }; 133 return retVal; 134 } 135 } 136 137 // Check if the item has already been added to the cart, if so the conditional below increments the quantity 138 // rather than adding the item a second time to the cart. 139 var exists = items.filter(function(existingItem) { 140 return existingItem.id === item.id; 141 }); 142 143 var newItem = { 144 id: item.id, 145 category_id: item.category_id, 146 name: item.title, 147 summary: item.introtext, 148 cost: item.cost, 149 cost_plus: item.cost_plus, 150 physical_item: item.physical_item, 151 allow_qty: item.allow_qty, 152 qty: Number(item.qty) || 1, 153 img: item.img, 154 type: item.type, 155 type_code: item.type_code 156 }; 157 158 if (item.attendees) { 159 newItem.attendees = item.attendees || []; 160 } 161 162 if (item.questions) { 163 newItem.questions = item.questions || []; 164 } 165 166 if (item.subItems) { 167 newItem.subItems = item.subItems || []; 168 } 169 170 if (item.password) { 171 newItem.license = { 172 password: item.password 173 }; 174 } 175 176 if (item.subscribers) { 177 newItem.subscribers = item.subscribers || []; 178 } 179 180 // for finance manager renewal 181 if (item.renewal) { 182 newItem.renewal = item.renewal 183 } 184 185 if (item.trial) { 186 newItem.trial = item.trial || "0" 187 } 188 189 if (exists.length === 0) { 190 items.push(newItem); 191 } else {
192 items.forEach(function(existingItem) { 193 if (existingItem.id === item.id && item.type !== "pkg") { 194 if ( 195 Number(existingItem.qty) + Number(newItem.qty) > 196 APP_CONFIG.ITEM_MAX_QTY 197 ) { 198 existingItem.qty = APP_CONFIG.ITEM_MAX_QTY; 199 } else { 200 existingItem.qty = Number(existingItem.qty) + Number(newItem.qty); 201 } 202 existingItem = newItem; 203 } 204 }); 205 } 206 this.getTotal(); 207 208 return retVal; 209 }; 210 211 this.removeOrderItem = function(idx) { 212 if (this.order.details.items.length > 0) { 213 this.order.details.items.splice(idx, 1); 214 } 215 this.getTotal(); 216 }; 217 218 this.removeAttendees = function(idx, qty) { 219 if ( 220 this.order.details.items.length > 0 && 221 this.order.details.items[idx].attendees 222 ) { 223 this.order.details.items[idx].attendees = this.order.details.items[ 224 idx 225 ].attendees.slice(0, qty); 226 } 227 this.getTotal(); 228 }; 229 230 this.addCoupon = function(coupon) { 231 this.order.details.coupon = coupon; 232 this.getTotal(); 233 }; 234 235 this.removeCoupon = function() { 236 this.order.details.coupon = {}; 237 this.getTotal(); 238 }; 239 240 this.getTotal = function() { 241 var total = 0; 242 var hasPlus = Number(this.order.school.plus); 243 if (!hasPlus || self.plusTriggeredByOrder) { 244 var subPlusItem = new Array(); 245 var basePlusItem = this.order.details.items.filter(function(item) { 246 return item.type === "plus"; 247 }); 248 if (basePlusItem.length > 0) { 249 self.order.school.plus = 1; 250 hasPlus = 1; 251 self.plusTriggeredByOrder = 1; 252 } else if (basePlusItem.length === 0) { 253 angular.forEach(self.order.details.items, function(item) { 254 if (item.type === "pkg") { 255 subPlusItem = item.subItems.filter(function(subItem) { 256 return subItem.type === "plus"; 257 }); 258 } 259 if (subPlusItem.length > 0) { 260 self.order.school.plus = 1; 261 hasPlus = 1; 262 self.plusTriggeredByOrder = 1; 263 } else { 264 self.order.school.plus = 0; 265 hasPlus = 0; 266 self.plusTriggeredByOrder = 0; 267 } 268 }); 269 } 270 } 271 272 this.order.details.items.forEach(function(item) { 273 var adjustedCost = calculateLineCost(item); 274 total += adjustedCost; 275 }); 276 this.order.details.total = total; 277 this.persistOrder(); 278 return total; 279 }; 280 281 this.processOrder = function(data=null) { 282 if (data && this.order.payment.payment_method === 'pp') { 283 this.order.payment.paypal = { 284 orderID: data.orderID, 285 payerID: data.payerID 286 } 287 } 288 return $http.post("/store?format=json&task=order.save", this.order); 289 }; 290 291 this.startCart = function(data) { 292 return $http.post( 293 "/store?format=json&task=cartabandoned.api_addAbandoned", 294 data 295 ); 296 }; 297 298 this.completeCart = function(data) { 299 return $http.post( 300 "/store?format=json&task=cartabandoned.api_removeAbandoned", 301 data 302 ); 303 }; 304 305 var calculateLineCost = function(item) { 306 var price = item.cost; 307 var coupon = self.order.details.coupon; 308 var categoryExists = []; 309 var productExists = []; 310 if (Number(self.order.school.plus)) { 311 price = item.cost_plus; 312 } 313 // Handles multiple attendees for expos 314 item.attendees !== undefined && item.attendees.length > 0 ? item.qty = item.attendees.length + 1 : item.qty; 315 316 price *= item.qty; 317 if (coupon.id) { 318 if ( 319 angular.isDefined(coupon.coupon_categories) && 320 angular.isArray(coupon.coupon_categories) 321 ) { 322 categoryExists = coupon.coupon_categories.filter(function(category) { 323 return category == item.category_id; 324 }); 325 } 326 if ( 327 angular.isDefined(coupon.coupon_products) && 328 angular.isArray(coupon.coupon_products) 329 ) { 330 productExists = coupon.coupon_products.filter(function(product) { 331 return product == item.id; 332 }); 333 } 334 if (categoryExists.length > 0 || productExists.length > 0) { 335 switch (coupon.coupon_type) { 336 case "amountoff": 337 if (price - coupon.coupon_amount >= 0) { 338 price -= coupon.coupon_amount; 339 } 340 break; 341 case "percentoff": 342 price = price - price * (coupon.coupon_amount / 100); 343 break; 344 case "twoforone": 345 var individualPrice = price / item.qty; 346 price -= Math.floor(item.qty / 2) * individualPrice; 347 break; 348 default: 349 break; 350 } 351 } 352 } 353 return price; 354 }; 355 356 this.getOrder = function() { 357 return this.order; 358 }; 359 360 /** 361 * It's likely that this function will be $watched so I only want to go through 362 * the loop once, as oppossed to every digest cycle. 363 * If we start updating the cart between page loads we'll need to loop every time this is called 364 */ 365 this.getDuplicateItem = function(type) { 366 var _cartItem = false;
367 angular.forEach(self.order.details.items, function(item) { 368 if (item.type === type) { 369 _cartItem = item; 370 } 371 }); 372 373 return _cartItem; 374 }; 375 });
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.