public List <StorePurchase> GetPurchases(PurchasesInformation pInfo)
        {
            int failedTrns = 0;
            List <StorePurchase> purchases = new List <StorePurchase>();
            Exception            lastExcp  = null;

            foreach (var p in pInfo.Purchases)
            {
                try
                {
                    StorePurchase sP = GetPurchase(p.ProductIdentifier, p);
                    purchases.Add(sP);
                }
                catch (Exception e)
                {
                    failedTrns++;
                    lastExcp = e;
                }
            }
            if (lastExcp != null && failedTrns == pInfo.Purchases.Count)
            {
                throw lastExcp;
            }
            return(purchases);
        }
        public async Task <ActionResult <Purchase> > Add(PurchaseRequest request)
        {
            try
            {
                int userId   = int.Parse(User.Claims.FirstOrDefault(x => x.Type == "id")?.Value ?? "-1");
                var purchase = await _service.AddAsync(userId, request);

                var storePurchase = new StorePurchase
                {
                    Date             = purchase.TimeOfPurchase,
                    UserId           = userId,
                    PurchaseProducts = purchase.ReceiptPositions.Select(x => new PurchaseProduct
                    {
                        Count = x.Count,
                        Name  = x.Product.ProductName,
                        Price = x.Product.Price
                    }).ToList()
                };
                await _endpoint.Publish(storePurchase);

                return(Ok(purchase));
            }
            catch (ApiException e)
            {
                return(BadRequest(new ProblemDetails {
                    Detail = e.Message
                }));
            }
        }
        public StorePurchase GetPurchase(string productId, PurchaseResult purchaseResult)
        {
            StorePurchase p = new StorePurchase();

            string purchaseToken = purchaseResult.PurchaseId;

            if (string.IsNullOrEmpty(purchaseToken))
            {
                throw new StoreInvalidPurchaseException("PurchaseToken not found in Purchase Transaction Data");
            }

            if (string.IsNullOrEmpty(_iTunesStorePassword))
            {
                throw new StoreConfigurationException("iTunes Store Password cannot be empty");
            }

            try
            {
                p = ValidatePurchase(purchaseToken, purchaseResult, PurchaseEnvironment.Production);
            }
            catch (StoreResponseEnvironmentException)
            {
                p = ValidatePurchase(purchaseToken, purchaseResult, PurchaseEnvironment.Sandbox);
            }
            return(p);
        }
예제 #4
0
        public int GetPurchase(GxUserType gxStoreConfig, string productId, GxUserType gxPurchaseResult, GxUserType gxStorePurchase)
        {
            PurchaseResult purchase = JSONHelper.Deserialize <PurchaseResult>(gxPurchaseResult.ToJSonString());
            StorePurchase  sp       = null;
            int            errCode  = GetPurchaseImpl(gxStoreConfig, productId, purchase, out sp);

            if (errCode == 0)
            {
                gxStorePurchase.FromJSonString(sp.ToJson());
            }
            return(errCode);
        }
예제 #5
0
        private int GetPurchaseImpl(GxUserType gxStoreConfig, string productId, PurchaseResult purchase, out StorePurchase storePurchase)
        {
            storePurchase = new StorePurchase();
            int           errCode;
            IStoreManager storeMgr;

            ErrDescription = string.Empty;

            errCode = GetManager(gxStoreConfig, purchase.Platform, out storeMgr);
            if (errCode == 0)
            {
                try
                {
                    productId                  = productId.Trim();
                    purchase.PurchaseId        = purchase.PurchaseId.Trim();
                    purchase.ProductIdentifier = purchase.ProductIdentifier.Trim();
                    storePurchase              = storeMgr.GetPurchase(productId, purchase);
                    errCode = 0;
                }
                catch (StoreConfigurationException e)
                {
                    errCode        = 3;
                    ErrDescription = e.Message;
                }
                catch (StoreInvalidPurchaseException e)
                {
                    errCode        = 2;
                    ErrDescription = e.Message;
                }
                catch (StoreServerException e)
                {
                    errCode        = 4;
                    ErrDescription = e.Message;
                }
                catch (StoreException e)
                {
                    errCode        = 10;
                    ErrDescription = e.Message;
                }
            }
            ErrCode = errCode;
            return(errCode);
        }
        public List <StorePurchase> GetPurchases(PurchasesInformation pInfo)
        {
            List <StorePurchase> list = new List <StorePurchase>();

            foreach (PurchaseResult p in pInfo.Purchases)
            {
                p.TransactionData = pInfo.AppleReceipt;
                try {
                    StorePurchase sp = this.GetPurchase(p.ProductIdentifier, p);
                    if (!list.Contains(sp))
                    {
                        list.Add(sp);
                    }
                }
                catch
                {
                }
            }
            list.RemoveAll(sp => sp.ProductType == (int)ProductType.Subscription && sp.PurchaseStatus != PurchaseStatus.Valid);
            return(list);
        }
        private StorePurchase ParsePurchase(JObject purchase)
        {
            StorePurchase p;
            ProductType   pType = ProductType.Product;

            if (purchase.Contains("web_order_line_item_id"))
            {
                pType = ProductType.Subscription;
            }

            p = new StorePurchase()
            {
                ProductIdentifier = GetValueDefault("product_id", purchase, string.Empty),
                PurchaseId        = GetValueDefault("transaction_id", purchase, string.Empty),
                PurchaseDate      = GetDateValueFromMS("purchase_date_ms", purchase),
                ProductType       = (int)pType,
                PurchaseStatus    = PurchaseStatus.Valid,
                Custom            = new StorePurchaseCustom()
                {
                    Quantity      = Int32.Parse(GetValueDefault("quantity", purchase, string.Empty)),
                    IsTrialPeriod = GetValueDefault("is_trial_period", purchase, "false") == "true"
                }
            };

            if (pType == ProductType.Subscription)
            {
                p.Subscription = new StorePurchaseSubscription()
                {
                    Expiration     = GetDateValueFromMS("expires_date_ms", purchase),
                    FirstPurchased = GetDateValueFromMS("original_purchase_date_ms", purchase)
                };
                if (p.Subscription.Expiration < DateTime.Now)
                {
                    p.PurchaseStatus = PurchaseStatus.Expired;
                }
            }

            return(p);
        }
        private void InitializeImpl(PurchaseResult purchaseResult, out StorePurchase sP, out AndroidPublisherService service, out string packageName, out string token)
        {
            sP = null;
            Initialize();

            service = new AndroidPublisherService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = _credential,
                ApplicationName       = "GeneXus Application",
            });
            JObject trnData = JSONHelper.ReadJSON <JObject>(purchaseResult.TransactionData);

            packageName = (string)trnData["packageName"];
            token       = (string)trnData["purchaseToken"];
            if (string.IsNullOrEmpty(packageName))
            {
                throw new StoreInvalidPurchaseException("PackageName not found in Purchase Transaction Data");
            }
            if (string.IsNullOrEmpty(token))
            {
                throw new StoreInvalidPurchaseException("PurchaseToken not found in Purchase Transaction Data");
            }
        }
        public StorePurchase GetPurchase(string productId, PurchaseResult purchaseResult)
        {
            StorePurchase           sP;
            AndroidPublisherService service;
            string packageName, token;

            InitializeImpl(purchaseResult, out sP, out service, out packageName, out token);

            try
            {
                ProductType productType = GetPurchaseType(productId.Trim(), service, packageName.Trim());

                if (productType == ProductType.Subscription)
                {
                    SubscriptionPurchase s = service.Purchases.Subscriptions.Get(packageName, productId, token).Execute();

                    sP = new StorePurchase()
                    {
                        ProductIdentifier = productId,
                        PurchaseId        = token,
                        ProductType       = (int)ProductType.Subscription,
                        PurchaseDate      = Util.FromUnixTime(s.StartTimeMillis.GetValueOrDefault(0)),

                        Subscription = new StorePurchaseSubscription()
                        {
                            Expiration     = Util.FromUnixTime(s.ExpiryTimeMillis.GetValueOrDefault(0)),
                            FirstPurchased = Util.FromUnixTime(s.StartTimeMillis.GetValueOrDefault(0))
                        },

                        Custom = new StorePurchaseCustom()
                        {
                            Consumed             = false,
                            CancelReason         = s.CancelReason,
                            IsTrialPeriod        = false,
                            WillAutoRenew        = s.AutoRenewing.GetValueOrDefault(false),
                            Quantity             = 1,
                            OriginalPurchase     = purchaseResult,
                            AcknowledgementState = s.AcknowledgementState.Value
                        }
                    };

                    if (sP.Subscription.Expiration <= DateTime.Now)
                    {
                        sP.PurchaseStatus = PurchaseStatus.Expired;
                    }
                    else
                    {
                        if (sP.Custom.CancelReason.HasValue)
                        {
                            int cancelReason = sP.Custom.CancelReason.Value;
                            if (cancelReason == 0)
                            {
                                sP.PurchaseStatus = PurchaseStatus.Valid;
                            }
                            if (cancelReason == 1)
                            {
                                sP.PurchaseStatus = PurchaseStatus.Cancelled;
                            }
                        }
                        else
                        {
                            sP.PurchaseStatus = PurchaseStatus.Valid;
                        }
                    }
                }
                else
                {
                    ProductPurchase p = service.Purchases.Products.Get(packageName, productId, token).Execute();
                    sP = new StorePurchase()
                    {
                        ProductIdentifier = productId,
                        PurchaseId        = token,
                        ProductType       = (int)ProductType.Product,
                        PurchaseDate      = Util.FromUnixTime(p.PurchaseTimeMillis.GetValueOrDefault(0)),

                        Custom = new StorePurchaseCustom()
                        {
                            Consumed             = (p.ConsumptionState.HasValue && p.ConsumptionState.Value == 1),
                            IsTrialPeriod        = false,
                            Quantity             = 1,
                            OriginalPurchase     = purchaseResult,
                            AcknowledgementState = p.AcknowledgementState.Value
                        }
                    };
                    if (p.PurchaseState == 1)
                    {
                        sP.PurchaseStatus = PurchaseStatus.Cancelled;
                    }
                    else
                    {
                        if (p.ConsumptionState == 1)
                        {
                            sP.PurchaseStatus = PurchaseStatus.Expired;
                        }
                        else
                        {
                            sP.PurchaseStatus = PurchaseStatus.Valid;
                        }
                    }
                }
            }
            catch (GoogleApiException e)
            {
                switch (e.HttpStatusCode)
                {
                case System.Net.HttpStatusCode.NotFound:
                    throw new StorePurchaseNotFoundException("Google Play Purchase Token was not found");

                default:
                    throw new StoreException(e.Message, e);
                }
            }
            catch (Exception e)
            {
                throw new StoreException(e.Message, e);
            }
            return(sP);
        }
        private void ImportData(MusicDbContext context)
        {
            var artistData  = new DataTable();
            var releaseData = new DataTable();
            var copyData    = new DataTable();

            var peopleData           = new DataTable();
            var groupData            = new DataTable();
            var locationData         = new DataTable();
            var websiteData          = new DataTable();
            var concertData          = new DataTable();
            var festivalData         = new DataTable();
            var multiDayFestivalData = new DataTable();

            // Create Formats
            CreateReleaseFormats(context);

            // Retrieve necessary data
            using (var sqlConnect = new MySqlConnection(ConfigurationManager.ConnectionStrings["mysql.musicdb"].ConnectionString))
            {
                // Retrieve Artists
                var sqlCommand = new MySqlCommand("SELECT * FROM rvwartist", sqlConnect);
                var sqlAdapter = new MySqlDataAdapter(sqlCommand);
                sqlAdapter.Fill(artistData);

                // Retrieve Releases
                sqlCommand = new MySqlCommand(
                    @"SELECT d.artistID, d.position, r.releaseID, r.name, r.year, 
                        r.releasedby, r.isEP, r.isCompilation, r.isSingle, r.isSoundtrack,
                        r.isLiveAlbum, r.isRemixAlbum
                    FROM rvwartistdiscography d
                    INNER JOIN rvwrelease r 
                    ON d.releaseID = r.releaseID
                    ORDER BY d.artistID, d.position", sqlConnect);
                sqlAdapter = new MySqlDataAdapter(sqlCommand);
                sqlAdapter.Fill(releaseData);

                // Retrieve Copies
                sqlCommand = new MySqlCommand(
                    @"SELECT c.releaseID, c.purchaseDate, c.notes, c.formatID, 
                        c.price, c.markedPrice, c.salePrice, c.postage, c.calculateTax,
                        c.isGiftVoucherPurchase, c.isBirthdayMoneyPurchase, c.isXmasMoneyPurchase,
                        c.purchaseLocation, c.purchaseNotes, c.copyNotes,            
                        c.isGift, c.giftNotes, 
                        c.isCompetitionItem, c.competitionItemDetails,
                        c.isGigPurchase, c.gigHeadliner,
                        c.isOnlinePurchase, c.website,
                        c.includesDownloadCard, c.includesFlexidisc, c.includesCompactDiscs, c.includesDVDs, 
                        c.includesDownload, 
                        c.isSecondhand, c.isPledgeItem, c.isRecordStoreDayItem,
                        c.removedDate, c.removalNotes
                    FROM rvwreleasecopy c", sqlConnect);
                sqlAdapter = new MySqlDataAdapter(sqlCommand);
                sqlAdapter.Fill(copyData);
            }

            using (var oleDbConnect = new OleDbConnection(ConfigurationManager.ConnectionStrings["excel.import.data"].ConnectionString))
            {
                var oleDbCommand = new OleDbCommand("SELECT * FROM [People$]", oleDbConnect);
                var oleDbAdapter = new OleDbDataAdapter(oleDbCommand);
                oleDbAdapter.Fill(peopleData);

                oleDbCommand = new OleDbCommand("SELECT * FROM [Groups$]", oleDbConnect);
                oleDbAdapter = new OleDbDataAdapter(oleDbCommand);
                oleDbAdapter.Fill(groupData);

                oleDbCommand = new OleDbCommand("SELECT * FROM [Locations$]", oleDbConnect);
                oleDbAdapter = new OleDbDataAdapter(oleDbCommand);
                oleDbAdapter.Fill(locationData);

                oleDbCommand = new OleDbCommand("SELECT * FROM [Websites$]", oleDbConnect);
                oleDbAdapter = new OleDbDataAdapter(oleDbCommand);
                oleDbAdapter.Fill(websiteData);

                oleDbCommand = new OleDbCommand("SELECT * FROM [Concerts$]", oleDbConnect);
                oleDbAdapter = new OleDbDataAdapter(oleDbCommand);
                oleDbAdapter.Fill(concertData);

                oleDbCommand = new OleDbCommand("SELECT * FROM [Festivals$]", oleDbConnect);
                oleDbAdapter = new OleDbDataAdapter(oleDbCommand);
                oleDbAdapter.Fill(festivalData);

                oleDbCommand = new OleDbCommand("SELECT * FROM [Multi-Day Festivals$]", oleDbConnect);
                oleDbAdapter = new OleDbDataAdapter(oleDbCommand);
                oleDbAdapter.Fill(multiDayFestivalData);
            }

            var musicalEntities = ImportMusicalEntities(context, artistData);

            var groups         = ImportGroups(context, groupData);
            var locationGroups = groups.OfType <LocationGroup>().ToList();
            var eventGroups    = groups.OfType <EventGroup>().ToList();

            var locations = ImportLocations(context, locationData, locationGroups);
            var websites  = ImportWebsites(context, websiteData, groups.OfType <WebsiteGroup>().ToList());

            AttachWebsitesToLocationGroups(context, locationGroups, websites, websiteData);

            var people = ImportPeople(context, peopleData);

            var musicalEvents = new List <MusicalEvent>();

            ImportSingleDayEventData <Concert>(context, musicalEvents, eventGroups, musicalEntities.Values.ToList(), locations, people, concertData);
            ImportSingleDayEventData <Festival>(context, musicalEvents, eventGroups, musicalEntities.Values.ToList(), locations, people, festivalData);
            ImportMultiDayFestivalData(context, musicalEvents, groups.OfType <MultiDayFestivalGroup>().ToList(), eventGroups, musicalEntities.Values.ToList(), locations, people, multiDayFestivalData);

            List <Release> releases = new List <Release>();

            foreach (int artistID in musicalEntities.Keys)
            {
                var musicalEntity = musicalEntities[artistID];

                // Create Releases
                var artistReleases = releaseData.Select("artistID = " + artistID);
                foreach (var artistRelease in artistReleases)
                {
                    int    releaseID  = int.Parse(artistRelease["ReleaseID"].ToString());
                    string title      = artistRelease["Name"].ToString();
                    int    year       = int.Parse(artistRelease["Year"].ToString());
                    int    position   = int.Parse(artistRelease["Position"].ToString());
                    string releasedBy = artistRelease["ReleasedBy"].ToString();

                    // Tidy up name
                    title = title.Replace(" [OST]", "");
                    title = title.Replace(" (7\")", "");
                    title = title.Replace(" (Single)", "");

                    var release = new Release(title, year);

                    // Released By
                    release.ReleasedBy = releasedBy;

                    // ReleaseType
                    bool isEP     = Convert.ToBoolean(artistRelease["IsEP"]);
                    bool isSingle = Convert.ToBoolean(artistRelease["IsSingle"]);

                    var releaseType = ReleaseType.Album;
                    if (isEP)
                    {
                        releaseType = ReleaseType.EP;
                    }
                    if (isSingle)
                    {
                        releaseType = ReleaseType.Single;
                    }

                    release.ReleaseType = releaseType;

                    if (Convert.ToBoolean(artistRelease["IsCompilation"]))
                    {
                        release.Tags.Add(new Tag(Constants.RELEASE_TAG_COMPILATION));
                    }

                    if (Convert.ToBoolean(artistRelease["IsSoundtrack"]))
                    {
                        release.Tags.Add(new Tag(Constants.RELEASE_TAG_SOUNDTRACK));
                    }

                    if (Convert.ToBoolean(artistRelease["IsLiveAlbum"]))
                    {
                        release.Tags.Add(new Tag(Constants.RELEASE_TAG_LIVE));
                    }

                    if (Convert.ToBoolean(artistRelease["IsRemixAlbum"]))
                    {
                        release.Tags.Add(new Tag(Constants.RELEASE_TAG_REMIXES));
                    }

                    releases.Add(release);

                    // Create Copies
                    var releaseCopies = copyData.Select("releaseID = " + releaseID);
                    foreach (var releaseCopy in releaseCopies)
                    {
                        var copy = new Copy();

                        copy.Notes    = releaseCopy["CopyNotes"].ToString();
                        copy.OldNotes = releaseCopy["Notes"].ToString();

                        var dateAdded = releaseCopy["PurchaseDate"] as DateTime?;

                        // Configure all of the acquisition details...
                        if (Convert.ToBoolean(releaseCopy["isGift"]))
                        {
                            var giftDetails = new GiftDetails();

                            string[] giftNotes = releaseCopy["GiftNotes"].ToString().Split(new char[] { ';' }, StringSplitOptions.None);

                            if (giftNotes.Length == 2)
                            {
                                giftDetails.Occasion = giftNotes[0];

                                // From
                                foreach (var fromName in giftNotes[1].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                                {
                                    var person = people.First(p => p.Name == fromName);

                                    giftDetails.From.Add(person);
                                    person.GiftsGiven.Add(copy);
                                }
                            }

                            copy.AcquisitionDetails = giftDetails;
                        }
                        else if (Convert.ToBoolean(releaseCopy["isCompetitionItem"]))
                        {
                            var competitionItemDetails = new CompetitionItemDetails();
                            competitionItemDetails.Source = releaseCopy["CompetitionItemDetails"].ToString();
                            copy.AcquisitionDetails       = competitionItemDetails;
                        }
                        else
                        {
                            PurchaseDetails purchaseDetails = null;

                            var locationName     = releaseCopy["PurchaseLocation"].ToString();
                            var purchaseLocation = locations.Find(l => (l.FullName == locationName) || (l.OtherNames.Any(n => n.Name == locationName)));

                            if (Convert.ToBoolean(releaseCopy["isOnlinePurchase"]))
                            {
                                var onlinePurchase = new OnlinePurchase();

                                // Try and pull the purchase date from the notes via Regex
                                // If you can, that becomes the purchase date, and the existing
                                // purchase date becomes the received date
                                var matchedDate = Regex.Match(copy.OldNotes, @"(\d{2})/(\d{2})/(\d{4})");
                                if (matchedDate.Success)
                                {
                                    onlinePurchase.PurchaseDate = new DateTime(int.Parse(matchedDate.Groups[3].Value),
                                                                               int.Parse(matchedDate.Groups[2].Value),
                                                                               int.Parse(matchedDate.Groups[1].Value));
                                }

                                if (releaseCopy["Postage"] != DBNull.Value)
                                {
                                    onlinePurchase.Postage = decimal.Parse(releaseCopy["Postage"].ToString());
                                }

                                // Retrieve Website
                                if (releaseCopy["Website"] != DBNull.Value)
                                {
                                    var website = websites.Find(w => w.SortName == releaseCopy["Website"].ToString());
                                    if (website != null)
                                    {
                                        onlinePurchase.Website = website;
                                        website.Purchases.Add(copy);
                                    }
                                }

                                purchaseDetails = onlinePurchase;
                            }
                            else if (Convert.ToBoolean(releaseCopy["isGigPurchase"]))
                            {
                                var eventPurchase = new EventPurchase();

                                // Find Event...
                                var musicalEvent = musicalEvents.Find(c => (c.EventDate == dateAdded) && (c.Venue == purchaseLocation));
                                if (musicalEvent != null)
                                {
                                    eventPurchase.Event = musicalEvent;

                                    if (purchaseLocation != null)
                                    {
                                        purchaseLocation.Purchases.Add(copy);
                                    }
                                }

                                purchaseDetails = eventPurchase;
                            }
                            else
                            {
                                // By default, all copies are store purchases...
                                var storePurchase = new StorePurchase();
                                storePurchase.PurchaseLocation = purchaseLocation;

                                if (purchaseLocation != null)
                                {
                                    purchaseLocation.Purchases.Add(copy);
                                }

                                purchaseDetails = storePurchase;
                            }

                            // Setup the costs / prices...
                            if (releaseCopy["Price"] != DBNull.Value)
                            {
                                purchaseDetails.GrandTotal = decimal.Parse(releaseCopy["Price"].ToString());
                            }

                            if (releaseCopy["MarkedPrice"] != DBNull.Value)
                            {
                                purchaseDetails.MarkedPrice = decimal.Parse(releaseCopy["MarkedPrice"].ToString());
                            }

                            if (releaseCopy["SalePrice"] != DBNull.Value)
                            {
                                purchaseDetails.SalePrice = decimal.Parse(releaseCopy["SalePrice"].ToString());
                            }

                            // Calculate Tax, if necessary
                            if (Convert.ToBoolean(releaseCopy["CalculateTax"]))
                            {
                                if ((purchaseDetails.GrandTotal.HasValue) && (purchaseDetails.GrandTotal > 0))
                                {
                                    if ((purchaseDetails.SalePrice != null) && (purchaseDetails.SalePrice < purchaseDetails.GrandTotal))
                                    {
                                        purchaseDetails.Tax = purchaseDetails.GrandTotal - purchaseDetails.SalePrice;
                                    }
                                    else if ((purchaseDetails.MarkedPrice != null) && (purchaseDetails.MarkedPrice < purchaseDetails.GrandTotal))
                                    {
                                        purchaseDetails.Tax = purchaseDetails.GrandTotal - purchaseDetails.MarkedPrice;
                                    }
                                }
                            }

                            copy.AcquisitionDetails = purchaseDetails;
                        }

                        copy.AcquisitionDetails.DateAdded = dateAdded;
                        copy.AcquisitionDetails.Notes     = releaseCopy["PurchaseNotes"].ToString().Trim();

                        // Add in additional descriptive tags
                        if (Convert.ToBoolean(releaseCopy["IsPledgeItem"]))
                        {
                            copy.Tags.Add(new Tag(Constants.COPY_TAG_PLEDGE_ITEM));
                        }

                        if (Convert.ToBoolean(releaseCopy["IsSecondhand"]))
                        {
                            copy.Tags.Add(new Tag(Constants.COPY_TAG_SECONDHAND));
                        }

                        if (Convert.ToBoolean(releaseCopy["IsRecordStoreDayItem"]))
                        {
                            copy.Tags.Add(new Tag(Constants.COPY_TAG_RECORD_STORE_DAY_ITEM));
                        }

                        // Add in additional purchase tags
                        if (Convert.ToBoolean(releaseCopy["isGiftVoucherPurchase"]))
                        {
                            copy.Tags.Add(new Tag(Constants.COPY_TAG_GIFT_VOUCHER_PURCHASE));
                        }

                        if (Convert.ToBoolean(releaseCopy["isBirthdayMoneyPurchase"]))
                        {
                            copy.Tags.Add(new Tag(Constants.COPY_TAG_BIRTHDAY_MONEY_PURCHASE));
                        }

                        if (Convert.ToBoolean(releaseCopy["isXmasMoneyPurchase"]))
                        {
                            copy.Tags.Add(new Tag(Constants.COPY_TAG_XMAS_MONEY_PURCHASE));
                        }

                        // Add in copy elements
                        int formatID = int.Parse(releaseCopy["FormatID"].ToString());
                        switch (formatID)
                        {
                        case 1:         // CD
                            AddElementToCopy(context, copy, 1, "CD", 1);
                            break;

                        case 2:         // CD + DVD
                            AddElementToCopy(context, copy, 1, "CD", 1);
                            AddElementToCopy(context, copy, 1, "DVD", 2);
                            break;

                        case 3:         // 2CD
                            AddElementToCopy(context, copy, 2, "CD", 1);
                            break;

                        case 4:         // 2CD + DVD
                            AddElementToCopy(context, copy, 2, "CD", 1);
                            AddElementToCopy(context, copy, 1, "DVD", 2);
                            break;

                        case 5:         // 2CD + 2DVD
                            AddElementToCopy(context, copy, 2, "CD", 1);
                            AddElementToCopy(context, copy, 2, "DVD", 2);
                            break;

                        case 6:         // 3CD
                            AddElementToCopy(context, copy, 3, "CD", 1);
                            break;

                        case 7:         // LP
                            AddElementToCopy(context, copy, 1, "LP", 1);
                            break;

                        case 8:         // 2LP
                            AddElementToCopy(context, copy, 2, "LP", 1);
                            break;

                        case 9:         // 3LP
                            AddElementToCopy(context, copy, 3, "LP", 1);
                            break;

                        case 10:        // 4LP
                            AddElementToCopy(context, copy, 4, "LP", 1);
                            break;

                        case 11:        // Cassette
                            AddElementToCopy(context, copy, 1, "Cass", 1);
                            break;

                        case 12:        // Download
                            AddElementToCopy(context, copy, 1, "D/L", 1);
                            break;

                        case 13:        // 5LP
                            AddElementToCopy(context, copy, 5, "LP", 1);
                            break;

                        case 14:        // 6LP
                            AddElementToCopy(context, copy, 6, "LP", 1);
                            break;

                        case 15:        // 7LP
                            AddElementToCopy(context, copy, 7, "LP", 1);
                            break;

                        case 16:        // 8LP
                            AddElementToCopy(context, copy, 8, "LP", 1);
                            break;

                        case 17:        // 7"
                            AddElementToCopy(context, copy, 1, "7\"", 1);
                            break;

                        case 18:        // 10"
                            AddElementToCopy(context, copy, 1, "10\"", 1);
                            break;

                        case 19:        // Flexidisc
                            AddElementToCopy(context, copy, 1, "Flexi", 1);
                            break;

                        case 20:        // Download Card
                            AddElementToCopy(context, copy, 1, "D/L Card", 1);
                            break;
                        }

                        // Plus any additional Elements...
                        bool includesDownloadCard = Convert.ToBoolean(releaseCopy["IncludesDownloadCard"]);
                        bool includesFlexidisc    = Convert.ToBoolean(releaseCopy["IncludesFlexidisc"]);
                        int  includesCompactDiscs = Convert.ToInt32(releaseCopy["IncludesCompactDiscs"]);
                        int  includesDVDs         = Convert.ToInt32(releaseCopy["includesDVDs"]);
                        bool includesDownload     = Convert.ToBoolean(releaseCopy["IncludesDownload"]);

                        if ((includesCompactDiscs > 0) && (copy.Elements.Count(e => e.Format.Code == "CD") == 0))
                        {
                            AddElementToCopy(context, copy, includesCompactDiscs, "CD", copy.Elements.Count + 1);
                        }

                        if ((includesDVDs > 0) && (copy.Elements.Count(e => e.Format.Code == "DVD") == 0))
                        {
                            AddElementToCopy(context, copy, includesDVDs, "DVD", copy.Elements.Count + 1);
                        }

                        if ((includesFlexidisc) && (copy.Elements.Count(e => e.Format.Code == "Flexi") == 0))
                        {
                            AddElementToCopy(context, copy, 1, "Flexi", copy.Elements.Count + 1);
                        }

                        if ((includesDownloadCard) && (copy.Elements.Count(e => e.Format.Code == "D/L Card") == 0))
                        {
                            AddElementToCopy(context, copy, 1, "D/L Card", copy.Elements.Count + 1);
                        }

                        if ((includesDownload) && (copy.Elements.Count(e => e.Format.Code == "D/L") == 0))
                        {
                            AddElementToCopy(context, copy, 1, "D/L", copy.Elements.Count + 1);
                        }


                        // Finally, removal info... Hey, it has happened!
                        DateTime?removedDate = releaseCopy["RemovedDate"] as DateTime?;
                        if (removedDate.HasValue)
                        {
                            copy.Removed      = true;
                            copy.RemovedDate  = removedDate;
                            copy.RemovalNotes = releaseCopy["RemovalNotes"].ToString();
                        }

                        release.Copies.Add(copy);
                    }

                    // Create a Discography Entry
                    musicalEntity.Discography.Add(new DiscographyEntry(position, release));
                }
            }

            // Next, a bunch of painful split release stuff...

            // All of this is hard-coded, because... ahh, it's easier to just hard-code it all in, rather
            // than come up with some nice, elegant solution. I mean, presumably, once this has been completed
            // I won't need to run the import again, and it'll be fine just to have it hard-coded in.

            // Neil Finn / Paul Kelly
            var splitEntity  = musicalEntities.Values.First(a => a.SortName == "Kelly, Paul");
            var splitRelease = releases.Find(r => r.Title == "Goin' Your Way");

            var entries = splitEntity.Discography.Where(e => e.Position >= 10);

            foreach (var entry in entries)
            {
                entry.Position = entry.Position + 1;
            }

            splitEntity.Discography.Add(new DiscographyEntry(10, splitRelease));

            // Create a group for Neil Finn + Paul Kelly as well. (Mainly for live purposes).
            splitEntity = musicalEntities.Values.First(g => g.SortName == "Neil Finn + Paul Kelly");
            splitEntity.Discography.Add(new DiscographyEntry(1, splitRelease));

            // Courtney Barnett / Jen Cloher
            splitEntity = musicalEntities.Values.First(a => a.SortName == "Cloher, Jen");

            splitRelease = releases.Find(r => r.Title == "History Eraser / Mount Beauty");
            splitEntity.Discography.Add(new DiscographyEntry(1, splitRelease));

            splitRelease = releases.Find(r => r.Title == "Needle in the Hay / Swan Street Swagger");
            splitEntity.Discography.Add(new DiscographyEntry(2, splitRelease));

            // David Sylvian / Robert Fripp
            splitEntity  = musicalEntities.Values.First(a => a.SortName == "Fripp, Robert");
            splitRelease = releases.Find(r => r.Title == "The First Day");

            splitEntity.Discography.Add(new DiscographyEntry(splitEntity.Discography.Count + 1, splitRelease));

            // David Byrne and Brian Eno
            splitEntity  = musicalEntities.Values.First(a => a.SortName == "Eno, Brian");
            splitRelease = releases.Find(r => r.Title == "Everything That Happens Will Happen Today");

            splitEntity.Discography.Add(new DiscographyEntry(splitEntity.Discography.Count + 1, splitRelease));

            // Brian Eno and David Byrne
            splitEntity  = musicalEntities.Values.First(a => a.SortName == "Byrne, David");
            splitRelease = releases.Find(r => r.Title == "My Life in the Bush of Ghosts");

            foreach (var entry in splitEntity.Discography)
            {
                entry.Position = entry.Position + 1;
            }

            splitEntity.Discography.Add(new DiscographyEntry(1, splitRelease));

            // Al Di Meola, John McLaughlin and Paco de Lucía
            splitRelease = releases.Find(r => r.Title == "Friday Night in San Francisco");

            splitEntity = musicalEntities.Values.First(a => a.SortName == "McLaughlin, John");
            splitEntity.Discography.Add(new DiscographyEntry(1, splitRelease));

            splitEntity = musicalEntities.Values.First(a => a.SortName == "de Lucía, Paco");
            splitEntity.Discography.Add(new DiscographyEntry(1, splitRelease));

            // John Lennon and Yoko Ono
            splitEntity  = musicalEntities.Values.First(a => a.SortName == "Ono, Yoko");
            splitRelease = releases.Find(r => r.Title == "Double Fantasy");

            foreach (var entry in splitEntity.Discography)
            {
                entry.Position = entry.Position + 1;
            }

            splitEntity.Discography.Add(new DiscographyEntry(1, splitRelease));

            // Suuns and Jerusalem in My Heart
            splitRelease = releases.Find(r => r.Title == "Suuns and Jerusalem in My Heart");

            splitEntity = musicalEntities.Values.First(a => a.SortName == "Jerusalem in My Heart");
            splitEntity.Discography.Add(new DiscographyEntry(1, splitRelease));

            splitEntity = musicalEntities.Values.First(g => g.SortName == "Suuns");
            splitEntity.Discography.Add(new DiscographyEntry(1, splitRelease));

            // Electric Light Orchestra and Olivia Newton-John
            splitRelease = releases.Find(r => r.Title == "Xanadu");

            splitEntity = musicalEntities.Values.First(a => a.SortName == "Newton-John, Olivia");
            splitEntity.Discography.Add(new DiscographyEntry(1, splitRelease));

            // 801 / Phil Manzanera
            splitRelease = releases.Find(r => r.Title == "Listen Now");

            splitEntity = musicalEntities.Values.First(a => a.SortName == "Manzanera, Phil");
            splitEntity.Discography.Add(new DiscographyEntry(2, splitRelease));


            // Finally, a cheap fix to get around the "Fire! Santa Rosa, Fire!" screwing up the
            // SetupPerformance() code. Damn comma in their name!
            splitEntity      = musicalEntities.Values.First(g => g.SortName == "Fire! Santa Rosa Fire!");
            splitEntity.Name = splitEntity.SortName = "Fire! Santa Rosa, Fire!";

            // Save everything to the database
            context.Set <Release>().AddRange(releases);
            context.SaveChanges();
        }
        private StorePurchase ValidatePurchase(string purchaseToken, PurchaseResult purchaseResult, PurchaseEnvironment env)
        {
            StorePurchase p = null;

            string responseString;
            string url = (env == PurchaseEnvironment.Production) ? APPLE_STORE_VALIDATION_URL_PROD : APPLE_STORE_VALIDATION_URL_SANDBOX;

            JObject inputObj = new JObject();

            inputObj.Put("receipt-data", purchaseResult.TransactionData.Trim());
            inputObj.Put("password", _iTunesStorePassword);

            string key = Util.GetHashString(inputObj.ToString());

            if (!dataCache.TryGetValue(key, out responseString))
            {
                HttpStatusCode code = DoPost(inputObj.ToString(), url, out responseString);
                switch (code)
                {
                case HttpStatusCode.OK:
                    break;

                default:
                    throw new StoreInvalidPurchaseException("");
                }
                dataCache.TryAdd(key, responseString);
            }

            JObject jResponse = Util.FromJSonString(responseString);

            if (jResponse.Contains("status"))
            {
                int statusCode = (int)jResponse["status"];
                switch (statusCode)
                {
                case 21000:
                    throw new StoreResponsePurchaseException("The App Store could not read the JSON object you provided.");

                case 21002:
                    throw new StoreResponsePurchaseException("The data in the receipt-data property was malformed or missing.");

                case 21003:
                    throw new StoreResponsePurchaseException("The receipt could not be authenticated.");

                case 21004:
                    throw new StoreResponsePurchaseException("The shared secret you provided does not match the shared secret on file for your account.");

                case 21005:
                    throw new StoreResponsePurchaseException("The receipt server is not currently available.");

                case 21006:
                    throw new StoreResponsePurchaseException("Could not handle 21006 status response");

                case 21007:
                    string value;
                    dataCache.TryRemove(key, out value);
                    throw new StoreResponseEnvironmentException("This receipt is from the test environment, but it was sent to the production environment for verification. Send it to the test environment instead.");

                case 21008:
                    break;

                case 0:
                    break;

                default:
                    throw new StoreResponsePurchaseException($"Could not handle '{statusCode}' status response");
                }
                bool found = false;
                if (jResponse.Contains("receipt"))
                {
                    JObject receipt = (JObject)jResponse["receipt"];
                    if (receipt.Contains("in_app"))
                    {
                        JArray purchases = (JArray)receipt["in_app"];
                        foreach (JObject purchase in purchases)
                        {
                            if (purchase.Contains("transaction_id") && (string)purchase["transaction_id"] == purchaseToken)
                            {
                                found = true;
                                p     = ParsePurchase(purchase);
                                String ATT_ORIG_TRN_ID = "original_transaction_id";
                                if (p.PurchaseStatus == PurchaseStatus.Expired && p.ProductType == (int)ProductType.Subscription && purchase.Contains(ATT_ORIG_TRN_ID) && jResponse.Contains("latest_receipt_info"))
                                {
                                    String originalTransactionId = (string)purchase[ATT_ORIG_TRN_ID];
                                    JArray latestInfo            = (JArray)jResponse["latest_receipt_info"];
                                    List <StorePurchase> list    = new List <StorePurchase>();
                                    foreach (JObject latestPurchase in latestInfo)
                                    {
                                        if (latestPurchase.Contains(ATT_ORIG_TRN_ID) && (string)latestPurchase[ATT_ORIG_TRN_ID] == originalTransactionId)
                                        {
                                            p = ParsePurchase(latestPurchase);
                                            list.Add(p);
                                            if (p.PurchaseStatus == PurchaseStatus.Valid)
                                            {
                                                break;
                                            }
                                        }
                                    }
                                    if (p.PurchaseStatus != PurchaseStatus.Valid && list.Count > 0)
                                    {
                                        list = list.OrderByDescending(sp => sp.Subscription.Expiration).ToList();
                                        p    = list.First();
                                    }
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                    }
                }
                if (!found)
                {
                    throw new StorePurchaseNotFoundException("Purchase Id not found inside Apple Receipt");
                }
            }
            else
            {
                throw new StoreResponsePurchaseException("Aplle Store validation servers seems to be unavailable.");
            }
            if (p.ProductType == (int)ProductType.Subscription)
            {
                p.Custom.OriginalPurchase = purchaseResult;
            }
            return(p);
        }