// PayDividendVisitor::Trigger() is used in
// OTUnitDefinition::VisitAccountRecords()
// cppcheck-suppress unusedFunction
bool PayDividendVisitor::Trigger(
    const Account& theSharesAccount)  // theSharesAccount
                                      // is, say, a Pepsi
                                      // shares
// account.  Here, we'll send a dollars voucher
// to its owner.
{
    const std::int64_t lPayoutAmount =
        (theSharesAccount.GetBalance() * GetPayoutPerShare());

    if (lPayoutAmount <= 0) {
        otOut << "PayDividendVisitor::Trigger: nothing to pay, "
                 "since this account owns no shares. (Returning "
                 "true.)";
        return true;  // nothing to pay, since this account owns no shares.
                      // Success!
    }
    OT_ASSERT(false == GetNotaryID()->empty());
    const auto theNotaryID = GetNotaryID();
    OT_ASSERT(!GetPayoutUnitTypeId()->empty());
    const Identifier& payoutUnitTypeId_ = (Identifier::Factory());
    OT_ASSERT(!GetVoucherAcctID()->empty());
    const Identifier& theVoucherAcctID = (GetVoucherAcctID());
    Nym& theServerNym = const_cast<Nym&>(server_.GetServerNym());
    const auto theServerNymID = Identifier::Factory(theServerNym);
    const Identifier& RECIPIENT_ID = theSharesAccount.GetNymID();
    OT_ASSERT(!GetNymID()->empty());
    const Identifier& theSenderNymID = (GetNymID());
    OT_ASSERT(!GetMemo()->empty());
    const String& strMemo = (GetMemo());
    // Note: theSenderNymID is the originator of the Dividend Payout.
    // However, all the actual vouchers will be from "the server Nym" and
    // not from theSenderNymID. So then why is it even here? Because anytime
    // there's an error, the server will send to theSenderNymID instead of
    // RECIPIENT_ID (so the original sender can have his money back, instead of
    // just having it get lost in the ether.)
    bool bReturnValue = false;

    auto theVoucher{
        server_.API().Factory().Cheque(theNotaryID, Identifier::Factory())};

    OT_ASSERT(false != bool(theVoucher));

    // 10 minutes ==    600 Seconds
    // 1 hour    ==     3600 Seconds
    // 1 day    ==    86400 Seconds
    // 30 days    ==  2592000 Seconds
    // 3 months ==  7776000 Seconds
    // 6 months == 15552000 Seconds

    const time64_t VALID_FROM =
        OTTimeGetCurrentTime();  // This time is set to TODAY NOW
    const time64_t VALID_TO = OTTimeAddTimeInterval(
        VALID_FROM,
        OTTimeGetSecondsFromTime(OT_TIME_SIX_MONTHS_IN_SECONDS));  // This time
                                                                   // occurs in
    // 180 days (6 months).
    // Todo hardcoding.
    TransactionNumber lNewTransactionNumber = 0;
    auto context = server_.API().Wallet().mutable_ClientContext(
        theServerNym.ID(), theServerNym.ID());
    bool bGotNextTransNum =
        server_.GetTransactor().issueNextTransactionNumberToNym(
            context.It(), lNewTransactionNumber);  // We save the transaction
    // number on the server Nym (normally we'd discard it) because
    // when the cheque is deposited, the server nym, as the owner of
    // the voucher account, needs to verify the transaction # on the
    // cheque (to prevent double-spending of cheques.)
    if (bGotNextTransNum) {
        const bool bIssueVoucher = theVoucher->IssueCheque(
            lPayoutAmount,          // The amount of the cheque.
            lNewTransactionNumber,  // Requiring a transaction number prevents
                                    // double-spending of cheques.
            VALID_FROM,  // The expiration date (valid from/to dates) of the
                         // cheque
            VALID_TO,  // Vouchers are automatically starting today and lasting
                       // 6
                       // months.
            theVoucherAcctID,  // The asset account the cheque is drawn on.
            theServerNymID,    // Nym ID of the sender (in this case the server
                               // nym.)
            strMemo,  // Optional memo field. Includes item note and request
                      // memo.
            Identifier::Factory(RECIPIENT_ID));

        // All account crediting / debiting happens in the caller, in
        // server::Server.
        //    (AND it happens only ONCE, to cover ALL vouchers.)
        // Then in here, the voucher either gets send to the recipient, or if
        // error, sent back home to
        // the issuer Nym. (ALL the funds are removed, then the vouchers are
        // sent one way or the other.)
        // Any returned vouchers, obviously serve to notify the dividend payer
        // of where the errors were
        // (as well as give him the opportunity to get his money back.)
        //
        bool bSent = false;
        if (bIssueVoucher) {
            // All this does is set the voucher's internal contract string to
            // "VOUCHER" instead of "CHEQUE". We also set the server itself as
            // the remitter, which is unusual for vouchers, but necessary in the
            // case of dividends.
            //
            theVoucher->SetAsVoucher(theServerNymID, theVoucherAcctID);
            theVoucher->SignContract(theServerNym);
            theVoucher->SaveContract();

            // Send the voucher to the payments inbox of the recipient.
            //
            const auto strVoucher = String::Factory(*theVoucher);
            auto thePayment{server_.API().Factory().Payment(strVoucher)};

            OT_ASSERT(false != bool(thePayment));

            // calls DropMessageToNymbox
            bSent = server_.SendInstrumentToNym(
                theNotaryID,
                theServerNymID,  // sender nym
                RECIPIENT_ID,    // recipient nym
                *thePayment,
                "payDividend");    // todo: hardcoding.
            bReturnValue = bSent;  // <======= RETURN VALUE.
            if (bSent)
                m_lAmountPaidOut +=
                    lPayoutAmount;  // At the end of iterating all accounts, if
                                    // m_lAmountPaidOut is less than
            // lTotalPayoutAmount, then we return to rest
            // to the sender.
        } else {
            const auto strPayoutUnitTypeId = String::Factory(
                           Identifier::Factory(payoutUnitTypeId_)),
                       strRecipientNymID = String::Factory(RECIPIENT_ID);
            otErr << "PayDividendVisitor::Trigger: ERROR failed issuing "
                  << "voucher (to send to dividend payout recipient.) WAS "
                  << "TRYING TO PAY " << lPayoutAmount
                  << " of instrument definition " << strPayoutUnitTypeId
                  << " to Nym " << strRecipientNymID << ".\n";
        }
        // If we didn't send it, then we need to return the funds to where they
        // came from.
        //
        if (!bSent) {
            auto theReturnVoucher{server_.API().Factory().Cheque(
                theNotaryID, Identifier::Factory())};

            OT_ASSERT(false != bool(theReturnVoucher));

            const bool bIssueReturnVoucher = theReturnVoucher->IssueCheque(
                lPayoutAmount,          // The amount of the cheque.
                lNewTransactionNumber,  // Requiring a transaction number
                                        // prevents double-spending of cheques.
                VALID_FROM,  // The expiration date (valid from/to dates) of the
                             // cheque
                VALID_TO,    // Vouchers are automatically starting today and
                             // lasting 6 months.
                theVoucherAcctID,  // The asset account the cheque is drawn on.
                theServerNymID,    // Nym ID of the sender (in this case the
                                   // server nym.)
                strMemo,  // Optional memo field. Includes item note and request
                          // memo.
                Identifier::Factory(theSenderNymID));  // We're returning the
                                                       // money to its original
                                                       // sender.
            if (bIssueReturnVoucher) {
                // All this does is set the voucher's internal contract string
                // to
                // "VOUCHER" instead of "CHEQUE".
                //
                theReturnVoucher->SetAsVoucher(
                    theServerNymID, theVoucherAcctID);
                theReturnVoucher->SignContract(theServerNym);
                theReturnVoucher->SaveContract();

                // Return the voucher back to the payments inbox of the original
                // sender.
                //
                const auto strReturnVoucher =
                    String::Factory(*theReturnVoucher);
                auto theReturnPayment{
                    server_.API().Factory().Payment(strReturnVoucher)};

                OT_ASSERT(false != bool(theReturnPayment));

                // calls DropMessageToNymbox
                bSent = server_.SendInstrumentToNym(
                    theNotaryID,
                    theServerNymID,  // sender nym
                    theSenderNymID,  // recipient nym (original sender.)
                    *theReturnPayment,
                    "payDividend");  // todo: hardcoding.
                if (bSent)
                    m_lAmountReturned +=
                        lPayoutAmount;  // At the end of iterating all accounts,
                                        // if m_lAmountPaidOut+m_lAmountReturned
                                        // is less than lTotalPayoutAmount, then
                                        // we return the rest to the sender.
            } else {
                const auto strPayoutUnitTypeId =
                               String::Factory(payoutUnitTypeId_),
                           strSenderNymID = String::Factory(theSenderNymID);
                otErr << "PayDividendVisitor::Trigger: ERROR "
                         "failed issuing voucher (to return back to "
                         "the dividend payout initiator, after a failed "
                         "payment attempt to the originally intended "
                         "recipient.) WAS TRYING TO PAY "
                      << lPayoutAmount << " of instrument definition "
                      << strPayoutUnitTypeId << " to Nym " << strSenderNymID
                      << ".\n";
            }
        }   // if !bSent
    } else  // !bGotNextTransNum
    {
        const auto strPayoutUnitTypeId = String::Factory(payoutUnitTypeId_),
                   strRecipientNymID = String::Factory(RECIPIENT_ID);
        otErr << OT_METHOD << __FUNCTION__
              << ": ERROR!! Failed issuing next transaction number while "
              << "trying to send a voucher (while paying dividends.) "
              << "WAS TRYING TO PAY " << lPayoutAmount
              << " of instrument definition " << strPayoutUnitTypeId->Get()
              << " to Nym " << strRecipientNymID->Get() << ".\n";
    }

    return bReturnValue;
}
Esempio n. 2
0
int CALLBACK GetMemoData( LPVOID lp, int nGetType, LPVOID lpData, int nDataSize)
{
	switch( nGetType)
	{
	case _GET_MEMO:
		return GetMemo( lp, lpData, nDataSize);
	case _GET_TITLE:
		return GetTitle( lp, lpData, nDataSize);
	case _GET_FONT:
		return GetFont( lp, lpData, nDataSize);
	case _GET_FORECOLOR:
		return GetForeColor( lp, lpData, nDataSize);
	case _GET_BACKCOLOR:
		return GetBackColor( lp, lpData, nDataSize);
	case _GET_ICON:
		return GetIconIndex( lp);
	case _GET_ZORDER:
		return GetZOrder( lp);
	case _GET_WINDOWTYPE:
		return GetWindowType( lp);
	case _GET_RECT_NORMAL:
		return GetNormalRect( lp, lpData, nDataSize);
	case _GET_POINT_TITLE:
		return GetTitlePoint( lp, lpData, nDataSize);
	case _GET_POINT_ICON:
		return GetIconPoint( lp, lpData, nDataSize);
	case _GET_RECT_TITLE:
		return GetTitleRect( lp, lpData, nDataSize);
	case _GET_RECT_ICON:
		return GetIconRect( lp, lpData, nDataSize);

	case _GET_TIMERENABLE:
		return IsTimerEnable( lp);
	case _GET_TIMER_TYPE:
		return GetTimerType( lp);
	case _GET_TIMER_MONTH:
		return GetTimerMonth( lp);
	case _GET_TIMER_DAY:
		return GetTimerDay( lp);
	case _GET_TIMER_HOUR:
		return GetTimerHour( lp);
	case _GET_TIMER_MIN:
		return GetTimerMin( lp);
	case _GET_TIMER_WEEK:
		return GetTimerWeek( lp);
	case _GET_TIMER_SOUND:
		return GetTimerSound( lp, lpData, nDataSize);

	case _GET_LINKENABLE:
		return IsLink( lp);
	case _GET_LINK_FILE:
		return GetLinkFile( lp, lpData, nDataSize);
	case _GET_LINK_PARAM:
		return GetLinkParam( lp, lpData, nDataSize);

	case _GET_CREATE_YEAR:
		return GetCreateYear( lp);
	case _GET_CREATE_MONTH:
		return GetCreateMonth( lp);
	case _GET_CREATE_DAY:
		return GetCreateDay( lp);

	case _GET_DEF_FONT:
		return GetDefFont( lpData, nDataSize);
	case _GET_DEF_FORECLR:
		return GetDefForeColor( lpData, nDataSize);
	case _GET_DEF_BACKCLR:
		return GetDefBackColor( lpData, nDataSize);

	case _GET_VERSION:
		return VERSION_CODE;
	}
	return 0;
}